diff --git a/queue_job/README.rst b/queue_job/README.rst index 11ffe02698..bb430bafdb 100644 --- a/queue_job/README.rst +++ b/queue_job/README.rst @@ -388,13 +388,14 @@ be customized in ``Base._job_prepare_context_before_enqueue_keys``. When you are developing (ie: connector modules) you might want to bypass the queue job and run your code immediately. -To do so you can set `TEST_QUEUE_JOB_NO_DELAY=1` in your enviroment. +To do so you can set `QUEUE_JOB_NO_DELAY=1` in your enviroment. **Bypass jobs in tests** When writing tests on job-related methods is always tricky to deal with -delayed recordsets. To make your testing life easier -you can set `test_queue_job_no_delay=True` in the context. +delayed recordsets. To make your testing life easier, +or to run a delayed action immediately, +you can set `queue_job__no_delay=True` in the context. Tip: you can do this at test case level like this @@ -405,7 +406,7 @@ Tip: you can do this at test case level like this super().setUpClass() cls.env = cls.env(context=dict( cls.env.context, - test_queue_job_no_delay=True, # no jobs thanks + queue_job__no_delay=True, # no jobs thanks )) Then all your tests execute the job methods synchronously diff --git a/queue_job/delay.py b/queue_job/delay.py index 77c823c63c..d8bffeb7eb 100644 --- a/queue_job/delay.py +++ b/queue_job/delay.py @@ -4,11 +4,11 @@ import itertools import logging -import os import uuid from collections import defaultdict, deque from .job import Job +from .utils import must_run_without_delay _logger = logging.getLogger(__name__) @@ -217,17 +217,9 @@ def _has_to_execute_directly(self, vertices): In tests, prefer to use :func:`odoo.addons.queue_job.tests.common.trap_jobs`. """ - if os.getenv("TEST_QUEUE_JOB_NO_DELAY"): - _logger.warning( - "`TEST_QUEUE_JOB_NO_DELAY` env var found. NO JOB scheduled." - ) - return True envs = {vertex.recordset.env for vertex in vertices} for env in envs: - if env.context.get("test_queue_job_no_delay"): - _logger.warning( - "`test_queue_job_no_delay` ctx key found. NO JOB scheduled." - ) + if must_run_without_delay(env): return True return False diff --git a/queue_job/models/base.py b/queue_job/models/base.py index f2d3eb5aa3..051598ee6f 100644 --- a/queue_job/models/base.py +++ b/queue_job/models/base.py @@ -2,14 +2,12 @@ # License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html) import functools -import logging from odoo import api, models from ..delay import Delayable from ..job import DelayableRecordset - -_logger = logging.getLogger(__name__) +from ..utils import must_run_without_delay class Base(models.AbstractModel): @@ -216,8 +214,7 @@ def auto_delay_wrapper(self, *args, **kwargs): if ( self.env.context.get("job_uuid") or not context_delay - or self.env.context.get("_job_force_sync") - or self.env.context.get("test_queue_job_no_delay") + or must_run_without_delay(self.env) ): # we are in the job execution return auto_delay_wrapper.origin(self, *args, **kwargs) diff --git a/queue_job/readme/USAGE.rst b/queue_job/readme/USAGE.rst index e308e868c2..e43872fdce 100644 --- a/queue_job/readme/USAGE.rst +++ b/queue_job/readme/USAGE.rst @@ -254,13 +254,13 @@ be customized in ``Base._job_prepare_context_before_enqueue_keys``. When you are developing (ie: connector modules) you might want to bypass the queue job and run your code immediately. -To do so you can set `TEST_QUEUE_JOB_NO_DELAY=1` in your enviroment. +To do so you can set `QUEUE_JOB__NO_DELAY=1` in your enviroment. **Bypass jobs in tests** When writing tests on job-related methods is always tricky to deal with delayed recordsets. To make your testing life easier -you can set `test_queue_job_no_delay=True` in the context. +you can set `queue_job__no_delay=True` in the context. Tip: you can do this at test case level like this @@ -271,7 +271,7 @@ Tip: you can do this at test case level like this super().setUpClass() cls.env = cls.env(context=dict( cls.env.context, - test_queue_job_no_delay=True, # no jobs thanks + queue_job__no_delay=True, # no jobs thanks )) Then all your tests execute the job methods synchronously @@ -370,7 +370,7 @@ If you prefer, you can still test the whole thing in a single test, by calling When you are developing (ie: connector modules) you might want to bypass the queue job and run your code immediately. -To do so you can set ``TEST_QUEUE_JOB_NO_DELAY=1`` in your environment. +To do so you can set ``QUEUE_JOB__NO_DELAY=1`` in your environment. .. WARNING:: Do not do this in production @@ -378,7 +378,7 @@ To do so you can set ``TEST_QUEUE_JOB_NO_DELAY=1`` in your environment. You should use ``trap_jobs``, really, but if for any reason you could not use it, and still need to have job methods executed synchronously in your tests, you can -do so by setting ``test_queue_job_no_delay=True`` in the context. +do so by setting ``queue_job__no_delay=True`` in the context. Tip: you can do this at test case level like this @@ -389,7 +389,7 @@ Tip: you can do this at test case level like this super().setUpClass() cls.env = cls.env(context=dict( cls.env.context, - test_queue_job_no_delay=True, # no jobs thanks + queue_job__no_delay=True, # no jobs thanks )) Then all your tests execute the job methods synchronously without delaying any @@ -399,7 +399,7 @@ In tests you'll have to mute the logger like: @mute_logger('odoo.addons.queue_job.models.base') -.. NOTE:: in graphs of jobs, the ``test_queue_job_no_delay`` context key must be in at +.. NOTE:: in graphs of jobs, the ``queue_job__no_delay`` context key must be in at least one job's env of the graph for the whole graph to be executed synchronously diff --git a/queue_job/utils.py b/queue_job/utils.py new file mode 100644 index 0000000000..5134cd1068 --- /dev/null +++ b/queue_job/utils.py @@ -0,0 +1,40 @@ +# Copyright 2023 Camptocamp +# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html) + +import logging +import os + +_logger = logging.getLogger(__name__) + + +def must_run_without_delay(env): + """Retrun true if jobs have to run immediately. + + :param env: `odoo.api.Environment` instance + """ + # TODO: drop in v17 + if os.getenv("TEST_QUEUE_JOB_NO_DELAY"): + _logger.warning( + "`TEST_QUEUE_JOB_NO_DELAY` env var found. NO JOB scheduled. " + "Note that this key is deprecated: please use `QUEUE_JOB__NO_DELAY`" + ) + return True + + if os.getenv("QUEUE_JOB__NO_DELAY"): + _logger.warning("`QUEUE_JOB__NO_DELAY` env var found. NO JOB scheduled.") + return True + + # TODO: drop in v17 + deprecated_keys = ("_job_force_sync", "test_queue_job_no_delay") + for key in deprecated_keys: + if env.context.get(key): + _logger.warning( + "`%s` ctx key found. NO JOB scheduled. " + "Note that this key is deprecated: please use `queue_job__no_delay`", + key, + ) + return True + + if env.context.get("queue_job__no_delay"): + _logger.warning("`queue_job__no_delay` ctx key found. NO JOB scheduled.") + return True diff --git a/test_queue_job/tests/test_delay_mocks.py b/test_queue_job/tests/test_delay_mocks.py index a4f9861e33..6736b919b0 100644 --- a/test_queue_job/tests/test_delay_mocks.py +++ b/test_queue_job/tests/test_delay_mocks.py @@ -133,8 +133,8 @@ def test_mock_with_delay(self): self.assertEqual(delay_args, (1,)) self.assertDictEqual(delay_kwargs, {"foo": 2}) - @mute_logger("odoo.addons.queue_job.models.base") - @mock.patch.dict(os.environ, {"TEST_QUEUE_JOB_NO_DELAY": "1"}) + @mute_logger("odoo.addons.queue_job.utils") + @mock.patch.dict(os.environ, {"QUEUE_JOB__NO_DELAY": "1"}) def test_delay_graph_direct_exec_env_var(self): node = Delayable(self.env["test.queue.job"]).create_ir_logging( "test_delay_graph_direct_exec 1" @@ -157,10 +157,10 @@ def test_delay_graph_direct_exec_env_var(self): self.assertEqual(logs[0].message, "test_delay_graph_direct_exec 2") self.assertEqual(logs[1].message, "test_delay_graph_direct_exec 1") - @mute_logger("odoo.addons.queue_job.models.base") + @mute_logger("odoo.addons.queue_job.utils") def test_delay_graph_direct_exec_context_key(self): node = Delayable( - self.env["test.queue.job"].with_context(test_queue_job_no_delay=True) + self.env["test.queue.job"].with_context(queue_job__no_delay=True) ).create_ir_logging("test_delay_graph_direct_exec 1") node2 = Delayable(self.env["test.queue.job"]).create_ir_logging( "test_delay_graph_direct_exec 2" @@ -180,8 +180,8 @@ def test_delay_graph_direct_exec_context_key(self): self.assertEqual(logs[0].message, "test_delay_graph_direct_exec 2") self.assertEqual(logs[1].message, "test_delay_graph_direct_exec 1") - @mute_logger("odoo.addons.queue_job.models.base") - @mock.patch.dict(os.environ, {"TEST_QUEUE_JOB_NO_DELAY": "1"}) + @mute_logger("odoo.addons.queue_job.utils") + @mock.patch.dict(os.environ, {"QUEUE_JOB__NO_DELAY": "1"}) def test_delay_with_delay_direct_exec_env_var(self): model = self.env["test.queue.job"] model.with_delay().create_ir_logging("test_delay_graph_direct_exec 1") @@ -196,9 +196,9 @@ def test_delay_with_delay_direct_exec_env_var(self): self.assertEqual(len(logs), 1) self.assertEqual(logs[0].message, "test_delay_graph_direct_exec 1") - @mute_logger("odoo.addons.queue_job.models.base") + @mute_logger("odoo.addons.queue_job.utils") def test_delay_with_delay_direct_exec_context_key(self): - model = self.env["test.queue.job"].with_context(test_queue_job_no_delay=True) + model = self.env["test.queue.job"].with_context(queue_job__no_delay=True) model.with_delay().create_ir_logging("test_delay_graph_direct_exec 1") # jobs are executed directly logs = self.env["ir.logging"].search(