← Back to team overview

openerp-community team mailing list archive

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