'Run a given job taking care of the repetition.
:param job_cr: cursor to use to execute the job, safe to commit/rollback
:param job: job to be run (as a dictionary).
:param cron_cr: cursor holding lock on the cron job row, to use to update the next exec date,
must not be committed/rolled back!'

@classmethod
def _process_job(cls, job_cr, job, cron_cr):

    try:
        with api.Environment.manage():
            cron = api.Environment(job_cr, job['user_id'], {})[cls._name]
            now = fields.Datetime.context_timestamp(cron, datetime.now())
            nextcall = fields.Datetime.context_timestamp(cron, fields.Datetime.from_string(job['nextcall']))
            numbercall = job['numbercall']
            ok = False
            while ((nextcall < now) and numbercall):
                if (numbercall > 0):
                    numbercall -= 1
                if ((not ok) or job['doall']):
                    cron._callback(job['model'], job['function'], job['args'], job['id'])
                if numbercall:
                    nextcall += _intervalTypes[job['interval_type']](job['interval_number'])
                ok = True
            addsql = ''
            if (not numbercall):
                addsql = ',    active=False'
            cron_cr.execute((('UPDATE    ir_cron    SET    nextcall=%s,    numbercall=%s' + addsql) + '    WHERE    id=%s'), (fields.Datetime.to_string(nextcall.astimezone(pytz.UTC)), numbercall, job['id']))
            cron.invalidate_cache()
    finally:
        job_cr.commit()
        cron_cr.commit()
