Search code examples
pythoncronodoo-11

Odoo: cron method locks on writing attribute of an element with ir.cron reference


I have a cron that call the method my_cron_method() so defined (simplified):

class MyModel(models.Model):
  model_cron_id = fields.Many2one('ir.cron', 'Cron Scheduled Action')

  def my_cron_method(self):
    object_list = self.env['my.model']
    for object in object_list:
      print('ck_1')
      object.att_a = 123
      self.update_obj(object)
      print('ck_4')

  def update_obj(self, object):
    print('ck_2')
    object.att_b='abc'
    print('ck_3')
    return

The result when executed by cron is:

ck_1
ck_2

so the method "freezes" at object.att_b='abc' row.

These happens only if model_cron_id is valorized; if object_list has two elements and the valorized is the second, the first is completely elaborated.

I use PyCharm debug to follow step by step execution and when I confirm to execute the row it locks doing nothing else.

I tried to pause the execution a step before and do on console object._write({'att_a' : 123}) and it locks too. The rest of Odoo seems going well, only object on write is locked.

If I trigger the cron manually all goes well.

Any idea?

EDIT

I add the information on model_cron_id, because I discovered that it is the element that generates the problem.


Solution

  • After a long search and with some suggestion I arrived to a solution or better a workaround.

    I suppose the problem is that when in my_cron_method() the first attribute is setted object.att_a = 123 the object is locked an this propagate the lock to the cron object that is related (the same that is in execution).

    Following this suggestion (https://www.odoo.com/it_IT/forum/help-1/question/how-to-force-commit-in-a-loop-109751) I added self.env.cr.commit() after the attribute update. These solves the lock.

    There is another aspect to take present that comes from the Odoo documentation here https://www.odoo.com/documentation/12.0/reference/orm.html#field-access in case there are multiple attribute to update: use .write() to update all attribute at once.

    The complete solution is these:

    class MyModel(models.Model):
      att_a = fields.Integer('Attr_a')
      att_b = fields.Char('Attr_b')
      att_c = fields.Char('Attr_c')
      model_cron_id = fields.Many2one('ir.cron', 'Cron Scheduled Action')
    
      def my_cron_method(self):
        object_list = self.env['my.model']
        for object in object_list:
          object.att_a = 123
          self.env.cr.commit()
          self.update_obj(object)
    
      def update_obj(self, object):
        object.write({'att_b': 'abc', 'att_c': 'def'})
        return