openerp-community team mailing list archive
-
openerp-community team
-
Mailing list archive
-
Message #00114
lp:~openerp-community/openobject-server/edannenberg_frequentcronjobs into lp:openobject-server
Erik Dannenberg (bloopark systems) has proposed merging lp:~openerp-community/openobject-server/edannenberg_frequentcronjobs into lp:openobject-server.
Requested reviews:
OpenERP Core Team (openerp)
cleaned up code a bit, i accidently overwrote some new code in ir.xml
should have no conflicts now.
--
https://code.launchpad.net/~openerp-community/openobject-server/edannenberg_frequentcronjobs/+merge/39347
Your team OpenERP Community is subscribed to branch lp:~openerp-community/openobject-server/edannenberg_frequentcronjobs.
=== modified file 'bin/addons/base/ir/ir.xml'
--- bin/addons/base/ir/ir.xml 2010-10-17 18:16:21 +0000
+++ bin/addons/base/ir/ir.xml 2010-10-26 08:26:10 +0000
@@ -1428,7 +1428,7 @@
</field>
</record>
- <record id="ir_cron_view" model="ir.ui.view">
+ <record id="ir_cron_view" model="ir.ui.view">
<field name="name">ir.cron.form</field>
<field name="model">ir.cron</field>
<field name="type">form</field>
@@ -1436,8 +1436,8 @@
<form string="Scheduled Actions">
<field name="name"/>
<field name="active"/>
- <field name="user_id" />
- <field name="priority" />
+ <field name="user_id"/>
+ <field name="priority"/>
<notebook colspan="4">
<page string="Information">
<field name="interval_number"/>
@@ -1446,19 +1446,40 @@
<field name="nextcall"/>
<field name="numbercall"/>
<field name="doall"/>
+ <field name="add_runtime"/>
+ <separator string="Statistics" colspan="4"/>
+ <field name="track_runtime"/>
+ <newline/>
+ <group colspan="2" col="2" attrs="{'invisible':[('track_runtime', '!=', 1)]}">
+ <field name="runtime_avg_runs_max" readonly="False"/>
+ </group>
</page>
<page string="Technical Data" groups="base.group_extended">
<separator string="Action to Trigger" colspan="4"/>
<field name="model" groups="base.group_extended"/>
<field name="function"/>
<separator string="Arguments" colspan="4"/>
- <field colspan="4" name="args" nolabel="1"/>
+ <field colspan="4" name="args"/>
+ </page>
+ <page string="Statistical Data" attrs="{'invisible':[('track_runtime', '!=', 1)]}">
+ <field name="runtime_last" readonly="True"/>
+ <field name="runtime_last_on" readonly="True"/>
+ <newline/>
+ <field name="runtime_min" readonly="True"/>
+ <field name="runtime_min_on" readonly="True"/>
+ <newline/>
+ <field name="runtime_max" readonly="True"/>
+ <field name="runtime_max_on" readonly="True"/>
+ <newline/>
+ <field name="runtime_avg" readonly="True"/>
+ <field name="runtime_avg_on" readonly="True"/>
+ <field name="runtime_avg_runs_cur" readonly="True"/>
</page>
</notebook>
</form>
</field>
</record>
-
+
<record id="ir_cron_view_search" model="ir.ui.view">
<field name="name">ir.cron.search</field>
<field name="model">ir.cron</field>
=== modified file 'bin/addons/base/ir/ir_cron.py'
--- bin/addons/base/ir/ir_cron.py 2010-10-04 14:39:04 +0000
+++ bin/addons/base/ir/ir_cron.py 2010-10-26 08:26:10 +0000
@@ -50,13 +50,24 @@
'interval_number': fields.integer('Interval Number',help="Repeat every x."),
'interval_type': fields.selection( [('minutes', 'Minutes'),
('hours', 'Hours'), ('work_days','Work Days'), ('days', 'Days'),('weeks', 'Weeks'), ('months', 'Months')], 'Interval Unit'),
- 'numbercall': fields.integer('Number of Calls', help='Number of time the function is called,\na negative number indicates no limit'),
+ 'numbercall': fields.integer('Number of Calls', help='Number of times the function is called,\na negative number indicates no limit'),
'doall' : fields.boolean('Repeat Missed', help="Enable this if you want to execute missed occurences as soon as the server restarts."),
'nextcall' : fields.datetime('Next Execution Date', required=True, help="Next planned execution date for this scheduler"),
'model': fields.char('Object', size=64, help="Name of object whose function will be called when this scheduler will run. e.g. 'res.partener'"),
'function': fields.char('Function', size=64, help="Name of the method to be called on the object when this scheduler is executed."),
'args': fields.text('Arguments', help="Arguments to be passed to the method. e.g. (uid,)"),
- 'priority': fields.integer('Priority', help='0=Very Urgent\n10=Not urgent')
+ 'priority': fields.integer('Priority', help='0=Very Urgent\n10=Not urgent'),
+ 'track_runtime': fields.boolean('Track Runtime', help='Keep track of shortest/longest/last runtime of this job'),
+ 'runtime_min': fields.float('Fastest job run', digits=(12,6)),
+ 'runtime_min_on': fields.datetime('Date of fastest job run'),
+ 'runtime_max': fields.float('Longest job run', digits=(12,6)),
+ 'runtime_max_on': fields.datetime('Date of longest job run'),
+ 'runtime_avg': fields.float('Average job runtime', digits=(12,6)),
+ 'runtime_avg_runs_cur': fields.integer('Job runs in current interval'),
+ 'runtime_avg_runs_max': fields.integer('Iterations for average runtime', help='The amount of iterations to use for calculating the average runtime of this job. Use 0 for infinite runs. Example: Job runs once every hour, to reset average runtime calculation every week: 24*7=168 iterations.'),
+ 'runtime_avg_on': fields.datetime('Date last average interval started'),
+ 'runtime_last': fields.float('Duration of last job run', digits=(12,6)),
+ 'runtime_last_on': fields.datetime('Date of last job run'),
}
_defaults = {
@@ -67,7 +78,15 @@
'interval_type' : lambda *a: 'months',
'numbercall' : lambda *a: 1,
'active' : lambda *a: 1,
- 'doall' : lambda *a: 1
+ 'doall' : lambda *a: 1,
+ 'add_runtime' : lambda *a: 0,
+ 'track_runtime' : lambda *a: 0,
+ 'runtime_min' : lambda *a: 0,
+ 'runtime_max' : lambda *a: 0,
+ 'runtime_avg' : lambda *a: 0,
+ 'runtime_avg_runs_cur' : lambda *a: 0,
+ 'runtime_avg_runs_max' : lambda *a: 100,
+ 'runtime_last' : lambda *a: 0,
}
def _check_args(self, cr, uid, ids, context=None):
@@ -102,10 +121,10 @@
cr = db.cursor()
try:
if not pool._init:
- now = datetime.now()
+ now = DateTime.now()
cr.execute('select * from ir_cron where numbercall<>0 and active and nextcall<=now() order by priority')
for job in cr.dictfetchall():
- nextcall = datetime.strptime(job['nextcall'], '%Y-%m-%d %H:%M:%S')
+ nextcall = DateTime.strptime(job['nextcall'], '%Y-%m-%d %H:%M:%S')
numbercall = job['numbercall']
ok = False
@@ -113,35 +132,69 @@
if numbercall > 0:
numbercall -= 1
if not ok or job['doall']:
+ if job['track_runtime']:
+ callback_start = DateTime.now()
self._callback(cr, job['user_id'], job['model'], job['function'], job['args'])
+ if job['track_runtime']:
+ callback_runtime = DateTime.now() - callback_start
if numbercall:
- nextcall += _intervalTypes[job['interval_type']](job['interval_number'])
+ if job['add_runtime']:
+ nextcall = DateTime.now() + _intervalTypes[job['interval_type']](job['interval_number'])
+ else:
+ nextcall += _intervalTypes[job['interval_type']](job['interval_number'])
ok = True
- addsql = ''
+ addsql=''
if not numbercall:
addsql = ', active=False'
+ if job['track_runtime']:
+ addsql += self.get_tracking_sql(job, callback_start, callback_runtime)
+
cr.execute("update ir_cron set nextcall=%s, numbercall=%s"+addsql+" where id=%s", (nextcall.strftime('%Y-%m-%d %H:%M:%S'), numbercall, job['id']))
cr.commit()
-
- cr.execute('select min(nextcall) as min_next_call from ir_cron where numbercall<>0 and active and nextcall>=now()')
- next_call = cr.dictfetchone()['min_next_call']
- if next_call:
- next_call = time.mktime(time.strptime(next_call, '%Y-%m-%d %H:%M:%S'))
- else:
- next_call = int(time.time()) + 3600 # if do not find active cron job from database, it will run again after 1 day
-
- if not check:
- self.setAlarm(self._poolJobs, next_call, db_name, db_name)
-
- except Exception, ex:
- logger = netsvc.Logger()
- logger.notifyChannel('cron', netsvc.LOG_WARNING,
- 'Exception in cron:'+str(ex))
+ self.set_next_timer(cr, check)
finally:
cr.commit()
cr.close()
+
+ def get_tracking_sql(self, job, callback_start, callback_runtime):
+ sql_string = ''
+ callack_start_sql = callback_start.strftime('%Y-%m-%d %H:%M:%S')
+ callback_runtime_sql = str(callback_runtime.seconds)
+ sql_string += ", runtime_last="+callback_runtime_sql
+ sql_string += ", runtime_last_on='"+callack_start_sql+"'"
+ if callback_runtime <= job['runtime_min'] or job['runtime_min'] == 0.000000:
+ sql_string += ", runtime_min="+callback_runtime_sql
+ sql_string += ", runtime_min_on='"+callack_start_sql+"'"
+ if callback_runtime >= job['runtime_max']:
+ sql_string += ", runtime_max="+callback_runtime_sql
+ sql_string += ", runtime_max_on='"+callack_start_sql+"'"
+ avg_runs_current = job['runtime_avg_runs_cur']
+ avg_runs_runtime = (float(job['runtime_avg'])*float(avg_runs_current)+callback_runtime)/float((avg_runs_current+1))
+ if avg_runs_current == 0:
+ sql_string += ", runtime_avg_on='"+callack_start_sql+"'"
+ avg_runs_current += 1
+ if avg_runs_current > job['runtime_avg_runs_max'] and job['runtime_avg_runs_max'] != 0:
+ avg_runs_current = 0
+ sql_string += ", runtime_avg_runs_cur="+str(avg_runs_current)
+ sql_string += ", runtime_avg="+str(avg_runs_runtime.seconds)
+ return sql_string
+
+ def set_next_timer(self, cr, check=False):
+ cr.execute('select min(nextcall) as min_next_call from ir_cron where numbercall<>0 and active and nextcall>=now()')
+ next_call = cr.dictfetchone()['min_next_call']
+ if next_call:
+ next_call = time.mktime(time.strptime(next_call, '%Y-%m-%d %H:%M:%S'))
+ else:
+ next_call = int(time.time()) + 3600
+
+ if not check:
+ self.setAlarm(self._poolJobs, next_call, cr.dbname, cr.dbname)
+
+ def restart_timer(self, cr):
+ self.cancel(cr.dbname)
+ self.set_next_timer(cr)
def restart(self, dbname):
self.cancel(dbname)
@@ -150,19 +203,19 @@
def create(self, cr, uid, vals, context=None):
res = super(ir_cron, self).create(cr, uid, vals, context=context)
cr.commit()
- self.restart(cr.dbname)
+ self.restart_timer(cr)
return res
def write(self, cr, user, ids, vals, context=None):
res = super(ir_cron, self).write(cr, user, ids, vals, context=context)
cr.commit()
- self.restart(cr.dbname)
+ self.restart_timer(cr)
return res
def unlink(self, cr, uid, ids, context=None):
res = super(ir_cron, self).unlink(cr, uid, ids, context=context)
cr.commit()
- self.restart(cr.dbname)
+ self.restart_timer(cr)
return res
ir_cron()
Follow ups