From 46d62d167cff8c927fc7bb6c4d2b3901dbce468f Mon Sep 17 00:00:00 2001 From: Adam Heinz Date: Thu, 21 Dec 2023 16:44:29 -0500 Subject: [PATCH 1/3] [IMP] queue_job: Improve context management. When the `queue_job_keep_context` context variable is set, always preserve the entire context. This honors the principle of least surprise, in that a developer can easily convert a record.method() call to record.with_delay().method() with the expectation that it will actually execute the same, simply at a later time. When the `queue_job_context_keys` context variable is set, preserve the given keys in addition to those normally specified by `_job_prepare_context_before_enqueue_keys`. --- queue_job/models/base.py | 16 ++++++++--- queue_job/tests/test_json_field.py | 46 ++++++++++++++++++++++++++++++ 2 files changed, 58 insertions(+), 4 deletions(-) diff --git a/queue_job/models/base.py b/queue_job/models/base.py index 3a68ffd11..9bdb4737b 100644 --- a/queue_job/models/base.py +++ b/queue_job/models/base.py @@ -245,15 +245,23 @@ def _job_store_values(self, job): @api.model def _job_prepare_context_before_enqueue_keys(self): - """Keys to keep in context of stored jobs - Empty by default for backward compatibility. - """ - return ("tz", "lang", "allowed_company_ids", "force_company", "active_test") + """Keys to keep in context of stored jobs""" + keys = self.env.context.get("queue_job_context_keys") + return ( + "tz", + "lang", + "allowed_company_ids", + "force_company", + "active_test", + *(keys or ()), + ) def _job_prepare_context_before_enqueue(self): """Return the context to store in the jobs Can be used to keep only safe keys. """ + if self.env.context.get("queue_job_keep_context"): + return self.env.context return { key: value for key, value in self.env.context.items() diff --git a/queue_job/tests/test_json_field.py b/queue_job/tests/test_json_field.py index f5bf760ff..e068426d7 100644 --- a/queue_job/tests/test_json_field.py +++ b/queue_job/tests/test_json_field.py @@ -32,6 +32,52 @@ def test_encoder_recordset(self): } self.assertEqual(json.loads(value_json), expected) + def test_encoder_recordset_context_keys(self): + demo_user = self.env.ref("base.user_demo") + context = { + **demo_user.context_get(), + "foo": "bar", + "baz": "zeb", + "queue_job_context_keys": ["foo"], + } + partner = self.env(user=demo_user, context=context).ref("base.main_partner") + value = partner + value_json = json.dumps(value, cls=JobEncoder) + expected_context = context.copy() + expected_context.pop("baz") + expected_context.pop("queue_job_context_keys") + expected_context.pop("uid") + expected = { + "uid": demo_user.id, + "_type": "odoo_recordset", + "model": "res.partner", + "ids": [partner.id], + "su": False, + "context": expected_context, + } + self.assertEqual(json.loads(value_json), expected) + + def test_encoder_recordset_keep_context(self): + demo_user = self.env.ref("base.user_demo") + context = { + **demo_user.context_get(), + "foo": "bar", + "queue_job_keep_context": True, + } + partner = self.env(user=demo_user, context=context).ref("base.main_partner") + value = partner + value_json = json.dumps(value, cls=JobEncoder) + expected_context = context.copy() + expected = { + "uid": demo_user.id, + "_type": "odoo_recordset", + "model": "res.partner", + "ids": [partner.id], + "su": False, + "context": expected_context, + } + self.assertEqual(json.loads(value_json), expected) + def test_encoder_recordset_list(self): demo_user = self.env.ref("base.user_demo") context = demo_user.context_get() From 5424f94979cd8672acaabd5f3cf7e19f91a2b2f4 Mon Sep 17 00:00:00 2001 From: Adam Heinz Date: Fri, 29 Aug 2025 10:06:06 -0400 Subject: [PATCH 2/3] [DOC] queue_job: Update USAGE.md --- queue_job/readme/USAGE.md | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/queue_job/readme/USAGE.md b/queue_job/readme/USAGE.md index deb6fe2ac..f16383ab2 100644 --- a/queue_job/readme/USAGE.md +++ b/queue_job/readme/USAGE.md @@ -276,7 +276,7 @@ Based on this configuration, we can tell that: - retries 10 to 15 postponed 30 seconds later - all subsequent retries postponed 5 minutes later -**Job Context** +#### Job Context The context of the recordset of the job, or any recordset passed in arguments of a job, is transferred to the job according to an @@ -284,8 +284,19 @@ allow-list. The default allow-list is ("tz", "lang", "allowed_company_ids", "force_company", "active_test"). It can be customized in -`Base._job_prepare_context_before_enqueue_keys`. **Bypass jobs on -running Odoo** +`Base._job_prepare_context_before_enqueue_keys`. + +When the `queue_job_context_keys` context variable is set, preserve +the given keys in addition to those normally specified by +`_job_prepare_context_before_enqueue_keys`. + +When the `queue_job_keep_context` context variable is set, always +preserve the entire context. This honors the principle of least +surprise, in that a developer can easily convert a record.method() +call to record.with_delay().method() with the expectation that it will +actually execute the same, simply at a later time. + +**Bypass jobs on running Odoo** When you are developing (ie: connector modules) you might want to bypass the queue job and run your code immediately. From 274f29c870cf9008746284f5fc5d9a5579a112e2 Mon Sep 17 00:00:00 2001 From: Adam Heinz Date: Fri, 29 Aug 2025 10:14:27 -0400 Subject: [PATCH 3/3] [DOC] queue_job: Update USAGE.md --- queue_job/readme/USAGE.md | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/queue_job/readme/USAGE.md b/queue_job/readme/USAGE.md index f16383ab2..05a4a8951 100644 --- a/queue_job/readme/USAGE.md +++ b/queue_job/readme/USAGE.md @@ -288,13 +288,24 @@ The default allow-list is ("tz", "lang", "allowed_company_ids", When the `queue_job_context_keys` context variable is set, preserve the given keys in addition to those normally specified by -`_job_prepare_context_before_enqueue_keys`. +`_job_prepare_context_before_enqueue_keys`. Examples: + +```python +# existing context +record.with_context(queue_job_context_keys=['a']).with_delay().func() +# new context +record.with_context(b=1, queue_job_context_keys=['b']).with_delay().func() +``` When the `queue_job_keep_context` context variable is set, always preserve the entire context. This honors the principle of least surprise, in that a developer can easily convert a record.method() call to record.with_delay().method() with the expectation that it will -actually execute the same, simply at a later time. +actually execute the same, simply at a later time. Example: + +```python +record.with_context(queue_job_keep_context=True).with_delay().func() +``` **Bypass jobs on running Odoo**