Skip to content

Commit efddad9

Browse files
author
Guewen Baconnier
committed
Fix mutability of job arguments
The model name, method name, recordset ids, arguments and keyword arguments must never ever be modified after the creation of a job. This change fix a bug when a job with a mutable argument see the content of the argument being modified during the execution of a job.
1 parent e5dfe4f commit efddad9

3 files changed

Lines changed: 35 additions & 6 deletions

File tree

queue_job/job.py

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -380,12 +380,6 @@ def store(self):
380380
'date_started': False,
381381
'date_done': False,
382382
'eta': False,
383-
'model_name': self.model_name,
384-
'method_name': self.method_name,
385-
'record_ids': self.recordset.ids,
386-
# TODO: use custom serializer for recordsets
387-
'args': self.args,
388-
'kwargs': self.kwargs,
389383
}
390384

391385
dt_to_string = odoo.fields.Datetime.to_string
@@ -403,9 +397,16 @@ def store(self):
403397
db_record.write(vals)
404398
else:
405399
date_created = dt_to_string(self.date_created)
400+
# The following values must never be modified after the
401+
# creation of the job
406402
vals.update({'uuid': self.uuid,
407403
'name': self.description,
408404
'date_created': date_created,
405+
'model_name': self.model_name,
406+
'method_name': self.method_name,
407+
'record_ids': self.recordset.ids,
408+
'args': self.args,
409+
'kwargs': self.kwargs,
409410
})
410411

411412
self.env[self.job_model_name].sudo().create(vals)

test_queue_job/models/test_models.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,12 @@ def job_with_retry_pattern__no_zero(self):
6767
def mapped(self, func):
6868
return super(TestQueueJob, self).mapped(func)
6969

70+
@job
71+
def job_alter_mutable(self, mutable_arg, mutable_kwarg=None):
72+
mutable_arg.append(2)
73+
mutable_kwarg['b'] = 2
74+
return mutable_arg, mutable_kwarg
75+
7076

7177
class TestQueueChannel(models.Model):
7278

test_queue_job/tests/test_job.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -380,6 +380,28 @@ def test_job_delay_model_method_multi(self):
380380
self.assertEquals(job_instance.method_name, 'mapped')
381381
self.assertEquals(['test1', 'test2'], job_instance.perform())
382382

383+
def test_job_with_mutable_arguments(self):
384+
""" Job with mutable arguments do not mutate on perform() """
385+
delayable = self.env['test.queue.job'].with_delay()
386+
job_instance = delayable.job_alter_mutable([1], mutable_kwarg={'a': 1})
387+
self.assertTrue(job_instance)
388+
result = job_instance.perform()
389+
self.assertEquals(
390+
result,
391+
([1, 2], {'a': 1, 'b': 2})
392+
)
393+
job_instance.set_done()
394+
# at this point, the 'args' and 'kwargs' of the job instance
395+
# might have been modified, but they must never be modified in
396+
# the queue_job table after their creation, so a new 'load' will
397+
# get the initial values.
398+
job_instance.store()
399+
# jobs are always loaded before being performed, so we simulate
400+
# this behavior here to check if we have the correct initial arguments
401+
job_instance = Job.load(self.env, job_instance.uuid)
402+
self.assertEquals(([1],), job_instance.args)
403+
self.assertEquals({'mutable_kwarg': {'a': 1}}, job_instance.kwargs)
404+
383405

384406
class TestJobModel(common.TransactionCase):
385407

0 commit comments

Comments
 (0)