diff --git a/openerp-cron-worker b/openerp-cron-worker index 4f86da928a5..12d58f3fec9 100755 --- a/openerp-cron-worker +++ b/openerp-cron-worker @@ -9,14 +9,58 @@ OpenERP server but depending on deployment needs, independent worker processes can be used. """ +import logging +import os +import signal +import sys + import openerp +# Also use the `openerp` logger for the main script. +_logger = logging.getLogger('openerp') + +# Variable keeping track of the number of calls to the signal handler defined +# below. This variable is monitored by ``quit_on_signals()``. +quit_signals_received = 0 + +# TODO copy/pasted from openerp-server +def signal_handler(sig, frame): + """ Signal handler: exit ungracefully on the second handled signal. + + :param sig: the signal number + :param frame: the interrupted stack frame or None + """ + global quit_signals_received + quit_signals_received += 1 + import openerp.addons.base + openerp.addons.base.ir.ir_cron.quit_signal_received = True + if quit_signals_received == 1 and openerp.addons.base.ir.ir_cron.job_in_progress: + _logger.info("Waiting for the current job to complete.") + print "Waiting for the current job to complete." + print "Hit Ctrl-C again to force shutdown." + if quit_signals_received > 1: + # logging.shutdown was already called at this point. + sys.stderr.write("Forced shutdown.\n") + os._exit(0) + +# TODO copy/pasted from openerp-server +def setup_signal_handlers(): + """ Register the signal handler defined above. """ + SIGNALS = map(lambda x: getattr(signal, "SIG%s" % x), "INT TERM".split()) + if os.name == 'posix': + map(lambda sig: signal.signal(sig, signal_handler), SIGNALS) + elif os.name == 'nt': + import win32api + win32api.SetConsoleCtrlHandler(lambda sig: signal_handler(sig, None), 1) + if __name__ == '__main__': + setup_signal_handlers() openerp.modules.module.initialize_sys_path() openerp.modules.loading.open_openerp_namespace() openerp.tools.config['log_handler'] = ['openerp.addons.base.ir.ir_cron:DEBUG'] openerp.netsvc.init_logger() import openerp.addons.base + print "OpenERP cron jobs worker. Hit Ctrl-C to exit." openerp.addons.base.ir.ir_cron.ir_cron._run(['xx']) # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/openerp/addons/base/ir/ir_cron.py b/openerp/addons/base/ir/ir_cron.py index 2514116cf19..0147e6b0bdc 100644 --- a/openerp/addons/base/ir/ir_cron.py +++ b/openerp/addons/base/ir/ir_cron.py @@ -38,6 +38,14 @@ from tools.translate import _ _logger = logging.getLogger(__name__) +# This variable can be set by a signal handler to stop the infinite loop in +# ir_cron._run() +quit_signal_received = False + +# This variable can be checked to know if ir_cron._run() is processing a job or +# sleeping. +job_in_progress = True + def str2tuple(s): return eval('tuple(%s)' % (s or '')) @@ -231,17 +239,22 @@ class ir_cron(osv.osv): @classmethod def _run(cls, db_names): - while True: + global quit_signal_received + while not quit_signal_received: t1 = time.time() for db_name in db_names: while(cls._acquire_job(db_name)): - pass + if quit_signal_received: + return t2 = time.time() t = t2 - t1 + global job_in_progress if t > 60: _logger.warning('Cron worker: processing all jobs took more than 1 minute to complete (%ss.).', int(t)) else: + job_in_progress = False time.sleep(60 - t) + job_in_progress = True def _try_lock(self, cr, uid, ids, context=None): """Try to grab a dummy exclusive write-lock to the rows with the given ids,