"""
Simple Scheduler
This scheduler is used to fire events across multiple databases. A database
master_scheduler is maintained with one event and one log table
Events are added by different databases in the master scheduler using the
`set_event` method and they are executed by the cron.
__main__ will call run
To install:
-----------
python install_lib.py [root] [password] master_scheduler
In cron:
--------
python [path]webnotes/utils/scheduler.py
"""
[docs]class Scheduler:
[docs] def connect(self):
if hasattr(self,'conn'): return
import webnotes.defs, webnotes.db
try:
self.conn = webnotes.db.Database(user='master_scheduler', password=webnotes.defs.db_password)
except Exception, e:
self.setup()
self.connect()
[docs] def set(self, event, interval, recurring, db_name=None):
"""
Add an event to the Event table in the master scheduler
"""
self.connect()
if not db_name:
import webnotes
db_name = webnotes.conn.cur_db_name
self.clear(db_name, event)
self.conn.sql("""insert into
Event (`db_name`, `event`, `interval`, next_execution, recurring)
values (%s, %s, %s, ADDTIME(NOW(), SEC_TO_TIME(%s)), %s)
""", (webnotes.conn.cur_db_name, event, interval, interval, recurring))
[docs] def get_events(self, db_name=None):
"""
Returns list of upcoming events
"""
self.connect()
if not db_name:
import webnotes
db_name = webnotes.conn.cur_db_name
return self.conn.sql("select * from Event where db_name=%s", db_name, as_dict=1)
[docs] def get_log(self, db_name=None):
"""
Returns log of events
"""
self.connect()
if not db_name:
import webnotes
db_name = webnotes.conn.cur_db_name
return self.conn.sql("select * from EventLog where db_name=%s limit 50", db_name, as_dict=1)
[docs] def clear(self, db_name, event):
"""
Clears the event
"""
self.connect()
self.conn.sql("delete from Event where `event`=%s and db_name=%s", (event, db_name))
[docs] def execute(self, db_name, event):
"""
Executes event in the specifed db
"""
import webnotes, webnotes.defs, webnotes.db
try:
webnotes.conn = webnotes.db.Database(user=db_name, password=webnotes.defs.db_password)
webnotes.session = {'user':'Administrator'}
module = '.'.join(event.split('.')[:-1])
method = event.split('.')[-1]
exec 'from %s import %s' % (module, method)
webnotes.conn.begin()
ret = locals()[method]()
webnotes.conn.commit()
webnotes.conn.close()
self.log(db_name, event, ret or 'Ok')
except Exception, e:
self.log(db_name, event, webnotes.getTraceback())
[docs] def log(self, db_name, event, traceback):
"""
Log an event error
"""
self.conn.sql("insert into `EventLog`(db_name, event, log, executed_on) values (%s, %s, %s, now())", \
(db_name, event, traceback))
# delete old logs
self.conn.sql("delete from EventLog where executed_on < subdate(curdate(), interval 30 day)")
[docs] def run(self):
"""
Run scheduled (due) events and reset time for recurring events
"""
el = self.conn.sql("""select `db_name`, `event`, `recurring`, `interval`
from `Event`
where next_execution < NOW()""", as_dict=1)
for e in el:
# execute the event
self.execute(e['db_name'], e['event'])
# if recurring, update next_execution
if e['recurring']:
self.conn.sql("update Event set next_execution = addtime(now(), sec_to_time(%s))", e['interval'])
# else clear
else:
self.clear(e['db_name'], e['event'])
[docs]def set_event(event, interval=60*60*24, recurring=1):
"""
Adds an event to the master scheduler
"""
return Scheduler().set(event, interval, recurring)
[docs]def cancel_event(event):
"""
Cancels an event
"""
import webnotes
return Scheduler().clear(webnotes.conn.cur_db_name, event)
# to be called from cron
if __name__=='__main__':
import os,sys
cgi_bin_path = os.path.sep.join(__file__.split(os.path.sep)[:-3])
sys.path.append(cgi_bin_path)
import webnotes
import webnotes.defs
sys.path.append(getattr(webnotes.defs,'modules_path',None))
sch = Scheduler()
sch.connect()
sch.run()