Func: Fedora Unified Network Controller を使ってみた(6.2)
前回 ( http://d.hatena.ne.jp/aaabbb_200904/20090922/1253627352 ) のような方針で。Pythonでスケジューラを作るとすると、 /etc/cron.d のようにPythonモジュールを置いておくディレクトリを作り、そのディレクトリ以下のファイル名を全て取得し、それらをPythonモジュールとしてimportする必要がある。
通常の import 文だと、引数としてstringを指定できないのだが、
sys=__import__('sys')
のような感じで、__import__を実行すると、上手くstringをimportできるらしい。
また、あるディレクトリ以下のファイル名を取得するには、
import os os.listdir()
が使用できる。
実際に、こんな感じでjob1, job2などのスケジュールを持ったディレクトリがある時、
$ ls -R cron.d/ cron.d/: holidays job1 job2 cron.d/holidays: __init__.py __init__.pyc september.py september.pyc cron.d/job1: __init__.py __init__.pyc row2.py row2.pyc cron.d/job2: __init__.py __init__.pyc row2.py row2.pyc
各スケジュールをモジュールとして読み込むには、次のようにすればよいようだ。
crond_path='cron.d'
sys.path.append(crond_path)
crontabs = os.listdir(crond_path)
crontabs.remove('holidays')
users=[]
for c in crontabs:
try:
users.append(__import__(c))
except Exception, inst:
print repr(inst)
なお、途中、crontabsから、holidaysを除いているが、こちらは休日データを収納するためで、直接スケジュールとして使っていないことによる。
メインのスケジュール部分はこんな感じになった。
while True: t=time.localtime() month=t[1] day=t[2] hour=t[3] min=t[4] second=t[5] dow=t[6] if (not second==0): time.sleep(0.1) continue print t for u in users: print repr(u) l=u.l for m in l: print repr(m) if (m.check_min(min) and m.check_hour(hour) and m.check_day(day) and m.check_month(month) and m.check_dow(dow)): print 'condition satisfied' if (m.command == None): print "don't perform command" break else: print 'perform command' thread=threading.Thread(target=m.command) try: thread.start() except Exception, inst: print repr(inst) else: print 'condition not satisfied' print "\n" time.sleep(1)
重要な部分は、
while True: if (not second==0): time.sleep(0.1) continue
のように、秒が0でないときには、sleepをはさんで、待ちにしているあたりと、
thread=threading.Thread(target=m.command) try: thread.start() except Exception, inst: print repr(inst)
threading と例外を使って、各モジュールが長時間かかる場合にスケジューラが引きずられないようにすることと、モジュール自体に文法ミス, sys.exit などがあった場合にスケジューラが落ちないようにすることだろうか。。
ちなみに、cron.d/job1 の中身も載せておく。
$ cat cron.d/job1/__init__.py
import holidays, row2
l=[holidays.september, row2]
$ cat cron.d/job1/row2.py
import subprocess, os, time
def command():
time.sleep(5)
p=subprocess.Popen('ps')
pid, sts = os.waitpid(p.pid,0)
print pid, sts
def check_min(n):
return True
def check_hour(n):
return True
def check_day(n):
return True
def check_month(n):
return True
def check_dow(n):
return True
なお、job1は、crontabでいうと、
* * * * * ps
に対応する。