Skip to content

Commit e8fa70c

Browse files
committed
[13.0][UPD] queue_job: use context to execute the job (optional)
1 parent b4bb7ac commit e8fa70c

5 files changed

Lines changed: 94 additions & 8 deletions

File tree

queue_job/job.py

Lines changed: 31 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
from datetime import datetime, timedelta
1212

1313
import odoo
14+
from odoo.tools.safe_eval import safe_eval
1415

1516
from .exception import FailedJobError, NoSuchJobError, RetryableJobError
1617

@@ -59,6 +60,7 @@ def __init__(
5960
description=None,
6061
channel=None,
6162
identity_key=None,
63+
keep_context=False,
6264
):
6365
self.recordset = recordset
6466
self.priority = priority
@@ -67,6 +69,7 @@ def __init__(
6769
self.description = description
6870
self.channel = channel
6971
self.identity_key = identity_key
72+
self.keep_context = keep_context
7073

7174
def __getattr__(self, name):
7275
if name in self.recordset:
@@ -88,6 +91,7 @@ def delay(*args, **kwargs):
8891
description=self.description,
8992
channel=self.channel,
9093
identity_key=self.identity_key,
94+
keep_context=self.keep_context,
9195
)
9296

9397
return delay
@@ -339,6 +343,7 @@ def enqueue(
339343
description=None,
340344
channel=None,
341345
identity_key=None,
346+
keep_context=False,
342347
):
343348
"""Create a Job and enqueue it in the queue. Return the job uuid.
344349
@@ -359,6 +364,7 @@ def enqueue(
359364
description=description,
360365
channel=channel,
361366
identity_key=identity_key,
367+
keep_context=keep_context,
362368
)
363369
if new_job.identity_key:
364370
existing = new_job.job_record_with_same_identity_key()
@@ -399,6 +405,7 @@ def __init__(
399405
description=None,
400406
channel=None,
401407
identity_key=None,
408+
keep_context=False,
402409
):
403410
""" Create a Job
404411
@@ -423,8 +430,8 @@ def __init__(
423430
:param identity_key: A hash to uniquely identify a job, or a function
424431
that returns this hash (the function takes the job
425432
as argument)
426-
:param env: Odoo Environment
427-
:type env: :class:`odoo.api.Environment`
433+
:param keep_context: Determine if the current context should be restored
434+
:type keep_context: :bool
428435
"""
429436
if args is None:
430437
args = ()
@@ -445,6 +452,7 @@ def __init__(
445452
self.recordset = recordset
446453

447454
self.env = env
455+
self.keep_context = keep_context
448456
self.job_model = self.env["queue.job"]
449457
self.job_model_name = "queue.job"
450458

@@ -594,8 +602,11 @@ def _store_values(self, create=False):
594602
"records": self.recordset,
595603
"args": self.args,
596604
"kwargs": self.kwargs,
605+
"context": "{}",
597606
}
598607
)
608+
if self.keep_context:
609+
vals.update({"context": str(self.env.context.copy())})
599610

600611
vals_from_model = self._store_values_from_model()
601612
# Sanitize values: make sure you cannot screw core values
@@ -615,6 +626,22 @@ def _store_values_from_model(self):
615626
vals = handler(self)
616627
return vals
617628

629+
def _get_record_context(self):
630+
"""
631+
Get the context to execute the job
632+
"""
633+
# return {}
634+
company_ids = []
635+
if self.company_id:
636+
company_ids = [self.company_id]
637+
context_txt = self.db_record().context or {}
638+
if isinstance(context_txt, str):
639+
context = safe_eval(context_txt)
640+
else:
641+
context = context_txt
642+
context.update({"job_uuid": self.uuid, "allowed_company_ids": company_ids})
643+
return context
644+
618645
@property
619646
def func_string(self):
620647
model = repr(self.recordset)
@@ -632,12 +659,8 @@ def func(self):
632659
# Because if you have many, you can have unexpected records due to ir.rule.
633660
# ir.rule use allowed_company_ids to load every records in many companies.
634661
# But most of the time, a job should be executed on a single company.
635-
company_ids = []
636-
if self.company_id:
637-
company_ids = [self.company_id]
638-
recordset = self.recordset.with_context(
639-
job_uuid=self.uuid, allowed_company_ids=company_ids
640-
)
662+
context = self._get_record_context()
663+
recordset = self.recordset.with_context(**context)
641664
return getattr(recordset, self.method_name)
642665

643666
@property

queue_job/models/base.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ def with_delay(
4444
description=None,
4545
channel=None,
4646
identity_key=None,
47+
keep_context=False,
4748
):
4849
""" Return a ``DelayableRecordset``
4950
@@ -81,6 +82,8 @@ def with_delay(
8182
the new job will not be added. It is either a
8283
string, either a function that takes the job as
8384
argument (see :py:func:`..job.identity_exact`).
85+
:param keep_context: boolean to set if the current context
86+
should be restored on the recordset (default: False).
8487
:return: instance of a DelayableRecordset
8588
:rtype: :class:`odoo.addons.queue_job.job.DelayableRecordset`
8689
@@ -108,6 +111,7 @@ def with_delay(
108111
description=description,
109112
channel=channel,
110113
identity_key=identity_key,
114+
keep_context=keep_context,
111115
)
112116

113117
def _patch_job_auto_delay(self, method_name, context_key=None):

queue_job/models/queue_job.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,12 @@ class QueueJob(models.Model):
5757
comodel_name="res.company", string="Company", index=True
5858
)
5959
name = fields.Char(string="Description", readonly=True)
60+
context = fields.Char(
61+
string="Context Value",
62+
default="{}",
63+
help="Context dictionary as Python expression, empty by default (Default: {})",
64+
readonly=True,
65+
)
6066

6167
model_name = fields.Char(string="Model", readonly=True)
6268
method_name = fields.Char(readonly=True)

queue_job/views/queue_job_views.xml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,9 @@
6060
<field name="exec_time" string="Time (s)" />
6161
</group>
6262
</group>
63+
<group name="context_grp">
64+
<field name="context" />
65+
</group>
6366
<group colspan="4">
6467
<div>
6568
<label for="retry" string="Current try / max. retries" />

test_queue_job/tests/test_job.py

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -579,6 +579,56 @@ def test_context_uuid(self):
579579
self.assertTrue(key_present)
580580
self.assertEqual(result["job_uuid"], test_job._uuid)
581581

582+
def test_context_custom_keep_context_default(self):
583+
"""
584+
Use with_delay without specify 'keep_context' key.
585+
So ensure the default False value to this params.
586+
So the context shouldn't be restored with the recordset.
587+
"""
588+
delayable = (
589+
self.env["test.queue.job"].with_context(world_origin=42).with_delay()
590+
)
591+
test_job = delayable.testing_method()
592+
self.assertEqual(test_job.db_record().context, "{}")
593+
expected_ctx = {
594+
"job_uuid": test_job.uuid,
595+
"allowed_company_ids": [test_job.company_id],
596+
}
597+
self.assertEqual(test_job._get_record_context(), expected_ctx)
598+
599+
def test_context_custom_keep_context_false(self):
600+
"""
601+
Use with_delay without specify by specifying keep_context to False.
602+
So the context shouldn't be restored with the recordset.
603+
"""
604+
delayable = (
605+
self.env["test.queue.job"]
606+
.with_context(world_origin=42)
607+
.with_delay(keep_context=False)
608+
)
609+
test_job = delayable.testing_method()
610+
self.assertEqual(test_job.db_record().context, "{}")
611+
expected_ctx = {
612+
"job_uuid": test_job.uuid,
613+
"allowed_company_ids": [test_job.company_id],
614+
}
615+
self.assertEqual(test_job._get_record_context(), expected_ctx)
616+
617+
def test_context_custom_keep_context_true(self):
618+
"""
619+
Use with_delay without specify by specifying keep_context to True.
620+
So the context should be restored with the recordset.
621+
"""
622+
recordset = self.env["test.queue.job"].with_context(world_origin=42)
623+
delayable = recordset.with_delay(keep_context=True)
624+
test_job = delayable.testing_method()
625+
self.assertEqual(test_job.db_record().context, str(recordset.env.context))
626+
expected_ctx = recordset.env.context.copy()
627+
expected_ctx.update(
628+
{"job_uuid": test_job.uuid, "allowed_company_ids": [test_job.company_id]}
629+
)
630+
self.assertEqual(test_job._get_record_context(), expected_ctx)
631+
582632
def test_override_channel(self):
583633
delayable = self.env["test.queue.job"].with_delay(channel="root.sub.sub")
584634
test_job = delayable.testing_method(return_context=True)

0 commit comments

Comments
 (0)