From f2bfda90718e7976e75e88f2cc81185a1d6b0dcf Mon Sep 17 00:00:00 2001 From: Guewen Baconnier Date: Thu, 19 Feb 2026 15:55:48 +0100 Subject: [PATCH 01/11] Add 'Allow Commit' option on job functions It is forbidden to commit inside a job, because it releases the job lock and can cause it to start again, while still being run, by the dead jobs requeuer. For some use cases, it may actually be legitimate, or at least be needed in the short term before actual updates in the code. A new option on the job function, false by default, allow to run the job in a new transaction, at the cost of an additional connection + transaction overhead. Related to #889 --- queue_job/controllers/main.py | 5 ++-- queue_job/job.py | 26 ++++++++++++++++---- queue_job/models/queue_job_function.py | 10 +++++++- queue_job/tests/common.py | 2 +- queue_job/tests/test_model_job_function.py | 2 ++ queue_job/views/queue_job_function_views.xml | 2 ++ 6 files changed, 38 insertions(+), 9 deletions(-) diff --git a/queue_job/controllers/main.py b/queue_job/controllers/main.py index e3dbd5309c..7e2345aaef 100644 --- a/queue_job/controllers/main.py +++ b/queue_job/controllers/main.py @@ -38,8 +38,9 @@ def _prevent_commit(cr): def forbidden_commit(*args, **kwargs): raise RuntimeError( "Commit is forbidden in queue jobs. " - "If the current job is a cron running as queue job, " - "modify it to run as a normal cron." + 'You may want to enable the "Allow Commit" option on the Job ' + "Function. Alternatively, if the current job is a cron running as " + "queue job, you can modify it to run as a normal cron." ) original_commit = cr.commit diff --git a/queue_job/job.py b/queue_job/job.py index 86407be3bb..249f441c88 100644 --- a/queue_job/job.py +++ b/queue_job/job.py @@ -8,6 +8,7 @@ import sys import uuid import weakref +from contextlib import contextmanager, nullcontext from datetime import datetime, timedelta from random import randint @@ -427,10 +428,6 @@ def __init__( self.method_name = func.__name__ self.recordset = recordset - self.env = env - self.job_model = self.env["queue.job"] - self.job_model_name = "queue.job" - self.job_config = ( self.env["queue.job.function"].sudo().job_config(self.job_function_name) ) @@ -508,7 +505,12 @@ def perform(self): """ self.retry += 1 try: - self.result = self.func(*tuple(self.args), **self.kwargs) + if self.job_config.allow_commit: + env_context_manager = self._with_temporary_env() + else: + env_context_manager = nullcontext() + with env_context_manager: + self.result = self.func(*tuple(self.args), **self.kwargs) except RetryableJobError as err: if err.ignore_retry: self.retry -= 1 @@ -528,6 +530,16 @@ def perform(self): return self.result + @contextmanager + def _with_temporary_env(self): + with self.env.registry.cursor() as new_cr: + env = self.recordset.env + self.recordset = self.recordset.with_env(env(cr=new_cr)) + try: + yield + finally: + self.recordset = self.recordset.with_env(env) + def _get_common_dependent_jobs_query(self): return """ UPDATE queue_job @@ -686,6 +698,10 @@ def __hash__(self): def db_record(self): return self.db_records_from_uuids(self.env, [self.uuid]) + @property + def env(self): + return self.recordset.env + @property def func(self): recordset = self.recordset.with_context(job_uuid=self.uuid) diff --git a/queue_job/models/queue_job_function.py b/queue_job/models/queue_job_function.py index ad034b46bc..8f36d824d1 100644 --- a/queue_job/models/queue_job_function.py +++ b/queue_job/models/queue_job_function.py @@ -28,7 +28,8 @@ class QueueJobFunction(models.Model): "related_action_enable " "related_action_func_name " "related_action_kwargs " - "job_function_id ", + "job_function_id " + "allow_commit", ) def _default_channel(self): @@ -79,6 +80,11 @@ def _default_channel(self): "enable, func_name, kwargs.\n" "See the module description for details.", ) + allow_commit = fields.Boolean( + help="Allows the job to commit transactions during execution. " + "Under the hood, this executes the job in a new database cursor, " + "which incurs a slight overhead.", + ) @api.depends("model_id.model", "method") def _compute_name(self): @@ -149,6 +155,7 @@ def job_default_config(self): related_action_func_name=None, related_action_kwargs={}, job_function_id=None, + allow_commit=False, ) def _parse_retry_pattern(self): @@ -184,6 +191,7 @@ def job_config(self, name): related_action_func_name=config.related_action.get("func_name"), related_action_kwargs=config.related_action.get("kwargs", {}), job_function_id=config.id, + allow_commit=config.allow_commit, ) def _retry_pattern_format_error_message(self): diff --git a/queue_job/tests/common.py b/queue_job/tests/common.py index 33173e3f2b..67db90b5c2 100644 --- a/queue_job/tests/common.py +++ b/queue_job/tests/common.py @@ -276,7 +276,7 @@ def _add_job(self, *args, **kwargs): def _prepare_context(self, job): # pylint: disable=context-overridden - job_model = job.job_model.with_context({}) + job_model = job.env["queue.job"].with_context({}) field_records = job_model._fields["records"] # Filter the context to simulate store/load of the job job.recordset = field_records.convert_to_write(job.recordset, job_model) diff --git a/queue_job/tests/test_model_job_function.py b/queue_job/tests/test_model_job_function.py index 84676fdb65..9095f2a55e 100644 --- a/queue_job/tests/test_model_job_function.py +++ b/queue_job/tests/test_model_job_function.py @@ -42,6 +42,7 @@ def test_function_job_config(self): ' "func_name": "related_action_foo",' ' "kwargs": {"b": 1}}' ), + "allow_commit": True, } ) self.assertEqual( @@ -53,5 +54,6 @@ def test_function_job_config(self): related_action_func_name="related_action_foo", related_action_kwargs={"b": 1}, job_function_id=job_function.id, + allow_commit=True, ), ) diff --git a/queue_job/views/queue_job_function_views.xml b/queue_job/views/queue_job_function_views.xml index a6e2ce402c..6c208b2b67 100644 --- a/queue_job/views/queue_job_function_views.xml +++ b/queue_job/views/queue_job_function_views.xml @@ -11,6 +11,7 @@ + @@ -25,6 +26,7 @@ + From feb8a0ffc81ea128cc731df1612c845fb610599b Mon Sep 17 00:00:00 2001 From: Guewen Baconnier Date: Thu, 19 Feb 2026 17:31:37 +0100 Subject: [PATCH 02/11] Add parameter to allow commit by default in jobs False on new databases, True on existing databases. Should always be False by default on future versions. --- queue_job/__manifest__.py | 1 + queue_job/data/ir_config_parameter_data.xml | 7 +++++++ .../migrations/18.0.2.2.0/post-migration.py | 13 +++++++++++++ queue_job/models/queue_job_function.py | 16 +++++++++++++++- 4 files changed, 36 insertions(+), 1 deletion(-) create mode 100644 queue_job/data/ir_config_parameter_data.xml create mode 100644 queue_job/migrations/18.0.2.2.0/post-migration.py diff --git a/queue_job/__manifest__.py b/queue_job/__manifest__.py index 158c54b1de..7f224a8098 100644 --- a/queue_job/__manifest__.py +++ b/queue_job/__manifest__.py @@ -21,6 +21,7 @@ "views/queue_job_menus.xml", "data/queue_data.xml", "data/queue_job_function_data.xml", + "data/ir_config_parameter_data.xml", ], "assets": { "web.assets_backend": [ diff --git a/queue_job/data/ir_config_parameter_data.xml b/queue_job/data/ir_config_parameter_data.xml new file mode 100644 index 0000000000..1cfdcd19bc --- /dev/null +++ b/queue_job/data/ir_config_parameter_data.xml @@ -0,0 +1,7 @@ + + + + queue_job.allow_commit_by_default + False + + diff --git a/queue_job/migrations/18.0.2.2.0/post-migration.py b/queue_job/migrations/18.0.2.2.0/post-migration.py new file mode 100644 index 0000000000..216fe49a8d --- /dev/null +++ b/queue_job/migrations/18.0.2.2.0/post-migration.py @@ -0,0 +1,13 @@ +# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html) +from openupgradelib import openupgrade + + +@openupgrade.migrate() +def migrate(env, version): + if not version: + return + + env["ir.config_parameter"].sudo().set_param( + "queue_job.allow_commit_by_default", True + ) + env["queue.job.function"].search([]).write({"allow_commit": True}) diff --git a/queue_job/models/queue_job_function.py b/queue_job/models/queue_job_function.py index 8f36d824d1..55593f795d 100644 --- a/queue_job/models/queue_job_function.py +++ b/queue_job/models/queue_job_function.py @@ -7,6 +7,7 @@ from collections import namedtuple from odoo import _, api, exceptions, fields, models, tools +from odoo.tools import str2bool from ..fields import JobSerialized @@ -81,6 +82,7 @@ def _default_channel(self): "See the module description for details.", ) allow_commit = fields.Boolean( + default=lambda self: self._default_allow_commit_by_default(), help="Allows the job to commit transactions during execution. " "Under the hood, this executes the job in a new database cursor, " "which incurs a slight overhead.", @@ -155,7 +157,19 @@ def job_default_config(self): related_action_func_name=None, related_action_kwargs={}, job_function_id=None, - allow_commit=False, + allow_commit=self._default_allow_commit_by_default(), + ) + + @api.model + def _default_allow_commit_by_default(self): + # We shoud not allow commit by default on job functions, this parameter + # is here for backward compatibility, a migration sets it by default on + # existing databases, but new databases will have it set to False by + # default. + return str2bool( + self.env["ir.config_parameter"] + .sudo() + .get_param("queue_job.allow_commit_by_default") ) def _parse_retry_pattern(self): From 2929b6d3f2de4723c145f94bb2178f6708f16748 Mon Sep 17 00:00:00 2001 From: Guewen Baconnier Date: Fri, 20 Feb 2026 15:15:18 +0100 Subject: [PATCH 03/11] Revert "Add parameter to allow commit by default in jobs" This reverts commit b4f3bec9ba7516635c3e8992da724499f708285e. --- queue_job/__manifest__.py | 1 - queue_job/data/ir_config_parameter_data.xml | 7 ------- .../migrations/18.0.2.2.0/post-migration.py | 13 ------------- queue_job/models/queue_job_function.py | 16 +--------------- 4 files changed, 1 insertion(+), 36 deletions(-) delete mode 100644 queue_job/data/ir_config_parameter_data.xml delete mode 100644 queue_job/migrations/18.0.2.2.0/post-migration.py diff --git a/queue_job/__manifest__.py b/queue_job/__manifest__.py index 7f224a8098..158c54b1de 100644 --- a/queue_job/__manifest__.py +++ b/queue_job/__manifest__.py @@ -21,7 +21,6 @@ "views/queue_job_menus.xml", "data/queue_data.xml", "data/queue_job_function_data.xml", - "data/ir_config_parameter_data.xml", ], "assets": { "web.assets_backend": [ diff --git a/queue_job/data/ir_config_parameter_data.xml b/queue_job/data/ir_config_parameter_data.xml deleted file mode 100644 index 1cfdcd19bc..0000000000 --- a/queue_job/data/ir_config_parameter_data.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - queue_job.allow_commit_by_default - False - - diff --git a/queue_job/migrations/18.0.2.2.0/post-migration.py b/queue_job/migrations/18.0.2.2.0/post-migration.py deleted file mode 100644 index 216fe49a8d..0000000000 --- a/queue_job/migrations/18.0.2.2.0/post-migration.py +++ /dev/null @@ -1,13 +0,0 @@ -# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html) -from openupgradelib import openupgrade - - -@openupgrade.migrate() -def migrate(env, version): - if not version: - return - - env["ir.config_parameter"].sudo().set_param( - "queue_job.allow_commit_by_default", True - ) - env["queue.job.function"].search([]).write({"allow_commit": True}) diff --git a/queue_job/models/queue_job_function.py b/queue_job/models/queue_job_function.py index 55593f795d..8f36d824d1 100644 --- a/queue_job/models/queue_job_function.py +++ b/queue_job/models/queue_job_function.py @@ -7,7 +7,6 @@ from collections import namedtuple from odoo import _, api, exceptions, fields, models, tools -from odoo.tools import str2bool from ..fields import JobSerialized @@ -82,7 +81,6 @@ def _default_channel(self): "See the module description for details.", ) allow_commit = fields.Boolean( - default=lambda self: self._default_allow_commit_by_default(), help="Allows the job to commit transactions during execution. " "Under the hood, this executes the job in a new database cursor, " "which incurs a slight overhead.", @@ -157,19 +155,7 @@ def job_default_config(self): related_action_func_name=None, related_action_kwargs={}, job_function_id=None, - allow_commit=self._default_allow_commit_by_default(), - ) - - @api.model - def _default_allow_commit_by_default(self): - # We shoud not allow commit by default on job functions, this parameter - # is here for backward compatibility, a migration sets it by default on - # existing databases, but new databases will have it set to False by - # default. - return str2bool( - self.env["ir.config_parameter"] - .sudo() - .get_param("queue_job.allow_commit_by_default") + allow_commit=False, ) def _parse_retry_pattern(self): From 649d680f77e17c31facc1e279f6805e8f233dc3d Mon Sep 17 00:00:00 2001 From: Guewen Baconnier Date: Fri, 20 Feb 2026 15:16:52 +0100 Subject: [PATCH 04/11] Improve documentation on allow commit --- queue_job/controllers/main.py | 3 ++- queue_job/models/queue_job_function.py | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/queue_job/controllers/main.py b/queue_job/controllers/main.py index 7e2345aaef..ab6b3f91d5 100644 --- a/queue_job/controllers/main.py +++ b/queue_job/controllers/main.py @@ -40,7 +40,8 @@ def forbidden_commit(*args, **kwargs): "Commit is forbidden in queue jobs. " 'You may want to enable the "Allow Commit" option on the Job ' "Function. Alternatively, if the current job is a cron running as " - "queue job, you can modify it to run as a normal cron." + "queue job, you can modify it to run as a normal cron. More details on: " + "https://github.com/OCA/queue/wiki/%5BDRAFT%5D-Upgrade-warning:-commits-inside-jobs" ) original_commit = cr.commit diff --git a/queue_job/models/queue_job_function.py b/queue_job/models/queue_job_function.py index 8f36d824d1..0fcd4fe269 100644 --- a/queue_job/models/queue_job_function.py +++ b/queue_job/models/queue_job_function.py @@ -83,7 +83,8 @@ def _default_channel(self): allow_commit = fields.Boolean( help="Allows the job to commit transactions during execution. " "Under the hood, this executes the job in a new database cursor, " - "which incurs a slight overhead.", + "which incurs an overhead as it requires an extra connection to " + "the database. " ) @api.depends("model_id.model", "method") From 63246bf20348b0c733dd66e9789d332148cd84d4 Mon Sep 17 00:00:00 2001 From: Guewen Baconnier Date: Tue, 24 Feb 2026 11:35:38 +0100 Subject: [PATCH 05/11] Fix missing job.env setter As the controller changes env on Job instances. --- queue_job/controllers/main.py | 4 +++- queue_job/job.py | 11 +++++++---- queue_job/tests/test_run_rob_controller.py | 6 ++++++ 3 files changed, 16 insertions(+), 5 deletions(-) diff --git a/queue_job/controllers/main.py b/queue_job/controllers/main.py index ab6b3f91d5..75e9c4e3cd 100644 --- a/queue_job/controllers/main.py +++ b/queue_job/controllers/main.py @@ -15,6 +15,7 @@ from odoo import SUPERUSER_ID, _, api, http, registry, tools from odoo.service.model import PG_CONCURRENCY_ERRORS_TO_RETRY +from odoo.tools import config from ..delay import chain, group from ..exception import FailedJobError, NothingToDoJob, RetryableJobError @@ -105,7 +106,8 @@ def _try_perform_job(cls, env, job): job.set_done() job.store() env.flush_all() - env.cr.commit() + if not config["test_enable"]: + env.cr.commit() _logger.debug("%s done", job) @classmethod diff --git a/queue_job/job.py b/queue_job/job.py index 249f441c88..c7a94e18e6 100644 --- a/queue_job/job.py +++ b/queue_job/job.py @@ -424,7 +424,6 @@ def __init__( raise TypeError("Job accepts only methods of Models") recordset = func.__self__ - env = recordset.env self.method_name = func.__name__ self.recordset = recordset @@ -477,10 +476,10 @@ def __init__( self.exc_message = None self.exc_info = None - if "company_id" in env.context: - company_id = env.context["company_id"] + if "company_id" in self.env.context: + company_id = self.env.context["company_id"] else: - company_id = env.company.id + company_id = self.env.company.id self.company_id = company_id self._eta = None self.eta = eta @@ -702,6 +701,10 @@ def db_record(self): def env(self): return self.recordset.env + @env.setter + def env(self, env): + self.recordset = self.recordset.with_env(env) + @property def func(self): recordset = self.recordset.with_context(job_uuid=self.uuid) diff --git a/queue_job/tests/test_run_rob_controller.py b/queue_job/tests/test_run_rob_controller.py index bb63bc82ec..1a15f4363a 100644 --- a/queue_job/tests/test_run_rob_controller.py +++ b/queue_job/tests/test_run_rob_controller.py @@ -15,3 +15,9 @@ def test_get_failure_values(self): self.assertEqual( rslt, {"exc_info": "info", "exc_name": "Exception", "exc_message": "zero"} ) + + def test_runjob_success(self): + job = self.env["queue.job"].with_delay()._test_job() + RunJobController._runjob(self.env, job) + self.assertEqual(job.state, "done") + self.assertEqual(job.db_record().state, "done") From 707abfe1136c99ed39e6e1a38b7ef41cc902808b Mon Sep 17 00:00:00 2001 From: Guewen Baconnier Date: Tue, 24 Feb 2026 16:00:20 +0100 Subject: [PATCH 06/11] Add failure retry in queue job test job --- queue_job/controllers/main.py | 13 +++++++++++++ queue_job/models/queue_job.py | 19 ++++++++++++++++--- 2 files changed, 29 insertions(+), 3 deletions(-) diff --git a/queue_job/controllers/main.py b/queue_job/controllers/main.py index 75e9c4e3cd..c669a13c07 100644 --- a/queue_job/controllers/main.py +++ b/queue_job/controllers/main.py @@ -244,6 +244,7 @@ def create_test_job( failure_rate=0, job_duration=0, commit_within_job=False, + failure_retry_seconds=0, ): """Create test jobs @@ -291,6 +292,12 @@ def create_test_job( except ValueError: max_retries = None + if failure_retry_seconds is not None: + try: + failure_retry_seconds = int(failure_retry_seconds) + except ValueError: + failure_retry_seconds = 0 + if size == 1: return self._create_single_test_job( priority=priority, @@ -300,6 +307,7 @@ def create_test_job( failure_rate=failure_rate, job_duration=job_duration, commit_within_job=commit_within_job, + failure_retry_seconds=failure_retry_seconds, ) if size > 1: @@ -312,6 +320,7 @@ def create_test_job( failure_rate=failure_rate, job_duration=job_duration, commit_within_job=commit_within_job, + failure_retry_seconds=failure_retry_seconds, ) return "" @@ -325,6 +334,7 @@ def _create_single_test_job( failure_rate=0, job_duration=0, commit_within_job=False, + failure_retry_seconds=0, ): delayed = ( http.request.env["queue.job"] @@ -338,6 +348,7 @@ def _create_single_test_job( failure_rate=failure_rate, job_duration=job_duration, commit_within_job=commit_within_job, + failure_retry_seconds=failure_retry_seconds, ) ) return "job uuid: %s" % (delayed.db_record().uuid,) @@ -354,6 +365,7 @@ def _create_graph_test_jobs( failure_rate=0, job_duration=0, commit_within_job=False, + failure_retry_seconds=0, ): model = http.request.env["queue.job"] current_count = 0 @@ -380,6 +392,7 @@ def _create_graph_test_jobs( failure_rate=failure_rate, job_duration=job_duration, commit_within_job=commit_within_job, + failure_retry_seconds=failure_retry_seconds, ) ) diff --git a/queue_job/models/queue_job.py b/queue_job/models/queue_job.py index f8c117fa2d..fd451818a7 100644 --- a/queue_job/models/queue_job.py +++ b/queue_job/models/queue_job.py @@ -12,7 +12,7 @@ from odoo.addons.base_sparse_field.models.fields import Serialized from ..delay import Graph -from ..exception import JobError +from ..exception import JobError, RetryableJobError from ..fields import JobSerialized from ..job import ( CANCELLED, @@ -459,10 +459,23 @@ def related_action_open_record(self): ) return action - def _test_job(self, failure_rate=0, job_duration=0, commit_within_job=False): + def _test_job( + self, + failure_rate=0, + job_duration=0, + commit_within_job=False, + failure_retry_seconds=0, + ): _logger.info("Running test job.") if random.random() <= failure_rate: - raise JobError("Job failed") + if failure_retry_seconds: + raise RetryableJobError( + f"Retryable job failed, will be retried in " + f"{failure_retry_seconds} seconds", + seconds=failure_retry_seconds, + ) + else: + raise JobError("Job failed") if job_duration: time.sleep(job_duration) if commit_within_job: From 65dc65c183e9760b33a4178dc813b19571a444df Mon Sep 17 00:00:00 2001 From: Guewen Baconnier Date: Tue, 24 Feb 2026 16:00:50 +0100 Subject: [PATCH 07/11] Simplify job env management --- queue_job/controllers/main.py | 9 ++++----- queue_job/job.py | 14 +++++++------- 2 files changed, 11 insertions(+), 12 deletions(-) diff --git a/queue_job/controllers/main.py b/queue_job/controllers/main.py index c669a13c07..938c5acb09 100644 --- a/queue_job/controllers/main.py +++ b/queue_job/controllers/main.py @@ -13,7 +13,7 @@ from psycopg2 import OperationalError, errorcodes from werkzeug.exceptions import BadRequest, Forbidden -from odoo import SUPERUSER_ID, _, api, http, registry, tools +from odoo import SUPERUSER_ID, _, api, http, tools from odoo.service.model import PG_CONCURRENCY_ERRORS_TO_RETRY from odoo.tools import config @@ -145,8 +145,7 @@ def _enqueue_dependent_jobs(cls, env, job): def _runjob(cls, env: api.Environment, job: Job) -> None: def retry_postpone(job, message, seconds=None): job.env.clear() - with registry(job.env.cr.dbname).cursor() as new_cr: - job.env = api.Environment(new_cr, SUPERUSER_ID, {}) + with job.in_temporary_env(): job.postpone(result=message, seconds=seconds) job.set_pending(reset_retry=False) job.store() @@ -182,6 +181,7 @@ def retry_postpone(job, message, seconds=None): # traceback in the logs we should have the traceback when all # retries are exhausted env.cr.rollback() + return except (FailedJobError, Exception) as orig_exception: buff = StringIO() @@ -189,8 +189,7 @@ def retry_postpone(job, message, seconds=None): traceback_txt = buff.getvalue() _logger.error(traceback_txt) job.env.clear() - with registry(job.env.cr.dbname).cursor() as new_cr: - job.env = job.env(cr=new_cr) + with job.in_temporary_env(): vals = cls._get_failure_values(job, traceback_txt, orig_exception) job.set_failed(**vals) job.store() diff --git a/queue_job/job.py b/queue_job/job.py index c7a94e18e6..b2d64c6d34 100644 --- a/queue_job/job.py +++ b/queue_job/job.py @@ -505,7 +505,7 @@ def perform(self): self.retry += 1 try: if self.job_config.allow_commit: - env_context_manager = self._with_temporary_env() + env_context_manager = self.in_temporary_env() else: env_context_manager = nullcontext() with env_context_manager: @@ -530,14 +530,14 @@ def perform(self): return self.result @contextmanager - def _with_temporary_env(self): + def in_temporary_env(self): with self.env.registry.cursor() as new_cr: - env = self.recordset.env - self.recordset = self.recordset.with_env(env(cr=new_cr)) + env = self.env + self._env = env(cr=new_cr) try: yield finally: - self.recordset = self.recordset.with_env(env) + self._env = env def _get_common_dependent_jobs_query(self): return """ @@ -702,7 +702,7 @@ def env(self): return self.recordset.env @env.setter - def env(self, env): + def _env(self, env): self.recordset = self.recordset.with_env(env) @property @@ -769,7 +769,7 @@ def model_name(self): @property def user_id(self): - return self.recordset.env.uid + return self.env.uid @property def eta(self): From a6459c4c636402a9e78583155ce0c3e425654b88 Mon Sep 17 00:00:00 2001 From: Guewen Baconnier Date: Fri, 27 Feb 2026 08:56:23 +0100 Subject: [PATCH 08/11] Update upgrade warning link --- queue_job/controllers/main.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/queue_job/controllers/main.py b/queue_job/controllers/main.py index 938c5acb09..02e05a6a96 100644 --- a/queue_job/controllers/main.py +++ b/queue_job/controllers/main.py @@ -42,7 +42,7 @@ def forbidden_commit(*args, **kwargs): 'You may want to enable the "Allow Commit" option on the Job ' "Function. Alternatively, if the current job is a cron running as " "queue job, you can modify it to run as a normal cron. More details on: " - "https://github.com/OCA/queue/wiki/%5BDRAFT%5D-Upgrade-warning:-commits-inside-jobs" + "https://github.com/OCA/queue/wiki/Upgrade-warning:-commits-inside-jobs" ) original_commit = cr.commit From 723e95dbdac231589c8fb61de51c7456f7c85e08 Mon Sep 17 00:00:00 2001 From: oca-ci Date: Thu, 9 Apr 2026 09:54:39 +0000 Subject: [PATCH 09/11] [UPD] Update queue_job.pot --- queue_job/i18n/queue_job.pot | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/queue_job/i18n/queue_job.pot b/queue_job/i18n/queue_job.pot index 3a3462af74..9c2a8985bc 100644 --- a/queue_job/i18n/queue_job.pot +++ b/queue_job/i18n/queue_job.pot @@ -52,6 +52,19 @@ msgstr "" msgid "Activity Type Icon" msgstr "" +#. module: queue_job +#: model:ir.model.fields,field_description:queue_job.field_queue_job_function__allow_commit +msgid "Allow Commit" +msgstr "" + +#. module: queue_job +#: model:ir.model.fields,help:queue_job.field_queue_job_function__allow_commit +msgid "" +"Allows the job to commit transactions during execution. Under the hood, this" +" executes the job in a new database cursor, which incurs an overhead as it " +"requires an extra connection to the database. " +msgstr "" + #. module: queue_job #: model:ir.model.fields,field_description:queue_job.field_queue_job__args msgid "Args" From a760887b0b8e3c20a68ca863ace1ea85c683a027 Mon Sep 17 00:00:00 2001 From: OCA-git-bot Date: Thu, 9 Apr 2026 09:56:37 +0000 Subject: [PATCH 10/11] [BOT] post-merge updates --- README.md | 2 +- queue_job/README.rst | 2 +- queue_job/__manifest__.py | 2 +- queue_job/static/description/index.html | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index aeafe8e05c..f824faf82c 100644 --- a/README.md +++ b/README.md @@ -24,7 +24,7 @@ addon | version | maintainers | summary --- | --- | --- | --- [base_export_async](base_export_async/) | 16.0.1.2.0 | | Asynchronous export with job queue [base_import_async](base_import_async/) | 16.0.1.2.1 | | Import CSV files in the background -[queue_job](queue_job/) | 16.0.2.13.2 | guewen sbidoul | Job Queue +[queue_job](queue_job/) | 16.0.3.0.0 | guewen sbidoul | Job Queue [queue_job_batch](queue_job_batch/) | 16.0.1.0.1 | | Job Queue Batch [queue_job_cron](queue_job_cron/) | 16.0.2.1.0 | | Scheduled Actions as Queue Jobs [queue_job_cron_jobrunner](queue_job_cron_jobrunner/) | 16.0.1.1.0 | ivantodorovich | Run jobs without a dedicated JobRunner diff --git a/queue_job/README.rst b/queue_job/README.rst index 1adbad629f..40c4be48c2 100644 --- a/queue_job/README.rst +++ b/queue_job/README.rst @@ -11,7 +11,7 @@ Job Queue !! This file is generated by oca-gen-addon-readme !! !! changes will be overwritten. !! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - !! source digest: sha256:2bd5c794474dd35dcd9b22179fa7d2690e791192862beaeeb674d8bedbb77558 + !! source digest: sha256:66ce31b496162c3eb2d775db0c116656cb3e4b67569e4c92e2eb99add0b19a48 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! .. |badge1| image:: https://img.shields.io/badge/maturity-Mature-brightgreen.png diff --git a/queue_job/__manifest__.py b/queue_job/__manifest__.py index 158c54b1de..72d0a71cac 100644 --- a/queue_job/__manifest__.py +++ b/queue_job/__manifest__.py @@ -2,7 +2,7 @@ { "name": "Job Queue", - "version": "16.0.2.13.2", + "version": "16.0.3.0.0", "author": "Camptocamp,ACSONE SA/NV,Odoo Community Association (OCA)", "website": "https://github.com/OCA/queue", "license": "LGPL-3", diff --git a/queue_job/static/description/index.html b/queue_job/static/description/index.html index bc065039fc..b4d6af8afe 100644 --- a/queue_job/static/description/index.html +++ b/queue_job/static/description/index.html @@ -372,7 +372,7 @@

Job Queue

!! This file is generated by oca-gen-addon-readme !! !! changes will be overwritten. !! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -!! source digest: sha256:2bd5c794474dd35dcd9b22179fa7d2690e791192862beaeeb674d8bedbb77558 +!! source digest: sha256:66ce31b496162c3eb2d775db0c116656cb3e4b67569e4c92e2eb99add0b19a48 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->

Mature License: LGPL-3 OCA/queue Translate me on Weblate Try me on Runboat

This addon adds an integrated Job Queue to Odoo.

From 4b240db80f0ca9ac631af243cc489fccb26d823a Mon Sep 17 00:00:00 2001 From: Weblate Date: Thu, 9 Apr 2026 09:56:47 +0000 Subject: [PATCH 11/11] Update translation files Updated by "Update PO files to match POT (msgmerge)" hook in Weblate. Translation: queue-16.0/queue-16.0-queue_job Translate-URL: https://translation.odoo-community.org/projects/queue-16-0/queue-16-0-queue_job/ --- queue_job/i18n/ca.po | 17 +++++++++++++++-- queue_job/i18n/de.po | 21 +++++++++++++++++---- queue_job/i18n/es.po | 21 +++++++++++++++++---- queue_job/i18n/fr.po | 21 +++++++++++++++++---- queue_job/i18n/it.po | 21 +++++++++++++++++---- queue_job/i18n/tr.po | 21 +++++++++++++++++---- queue_job/i18n/zh_CN.po | 17 +++++++++++++++-- 7 files changed, 115 insertions(+), 24 deletions(-) diff --git a/queue_job/i18n/ca.po b/queue_job/i18n/ca.po index 1a4ae1c1f5..4ad181bf58 100644 --- a/queue_job/i18n/ca.po +++ b/queue_job/i18n/ca.po @@ -59,6 +59,19 @@ msgstr "Estat de l'activitat" msgid "Activity Type Icon" msgstr "Icona del tipus d'activitat" +#. module: queue_job +#: model:ir.model.fields,field_description:queue_job.field_queue_job_function__allow_commit +msgid "Allow Commit" +msgstr "" + +#. module: queue_job +#: model:ir.model.fields,help:queue_job.field_queue_job_function__allow_commit +msgid "" +"Allows the job to commit transactions during execution. Under the hood, this " +"executes the job in a new database cursor, which incurs an overhead as it " +"requires an extra connection to the database. " +msgstr "" + #. module: queue_job #: model:ir.model.fields,field_description:queue_job.field_queue_job__args msgid "Args" @@ -927,8 +940,8 @@ msgstr "UUID" msgid "" "Unexpected format of Related Action for {}.\n" "Example of valid format:\n" -"{{\"enable\": True, \"func_name\": \"related_action_foo\", " -"\"kwargs\" {{\"limit\": 10}}}}" +"{{\"enable\": True, \"func_name\": \"related_action_foo\", \"kwargs\" " +"{{\"limit\": 10}}}}" msgstr "" #. module: queue_job diff --git a/queue_job/i18n/de.po b/queue_job/i18n/de.po index 41d291bb57..012cf8b950 100644 --- a/queue_job/i18n/de.po +++ b/queue_job/i18n/de.po @@ -60,6 +60,19 @@ msgstr "Aktivitätsstatus" msgid "Activity Type Icon" msgstr "Icon für Aktivitätstyp" +#. module: queue_job +#: model:ir.model.fields,field_description:queue_job.field_queue_job_function__allow_commit +msgid "Allow Commit" +msgstr "" + +#. module: queue_job +#: model:ir.model.fields,help:queue_job.field_queue_job_function__allow_commit +msgid "" +"Allows the job to commit transactions during execution. Under the hood, this " +"executes the job in a new database cursor, which incurs an overhead as it " +"requires an extra connection to the database. " +msgstr "" + #. module: queue_job #: model:ir.model.fields,field_description:queue_job.field_queue_job__args msgid "Args" @@ -952,13 +965,13 @@ msgstr "UUID" msgid "" "Unexpected format of Related Action for {}.\n" "Example of valid format:\n" -"{{\"enable\": True, \"func_name\": \"related_action_foo\", " -"\"kwargs\" {{\"limit\": 10}}}}" +"{{\"enable\": True, \"func_name\": \"related_action_foo\", \"kwargs\" " +"{{\"limit\": 10}}}}" msgstr "" "Unerwartetes Format der zugehörigen Aktion für {}.\n" "Beispiel für ein gültiges Format:\n" -"{{\"enable\": True, \"func_name\": \"related_action_foo\", " -"\"kwargs\" {{\"limit\": 10}}}}" +"{{\"enable\": True, \"func_name\": \"related_action_foo\", \"kwargs\" " +"{{\"limit\": 10}}}}" #. module: queue_job #. odoo-python diff --git a/queue_job/i18n/es.po b/queue_job/i18n/es.po index 0580170ec6..fe2f2fb8ff 100644 --- a/queue_job/i18n/es.po +++ b/queue_job/i18n/es.po @@ -59,6 +59,19 @@ msgstr "Estado de la actividad" msgid "Activity Type Icon" msgstr "Icono de tipo de actividad" +#. module: queue_job +#: model:ir.model.fields,field_description:queue_job.field_queue_job_function__allow_commit +msgid "Allow Commit" +msgstr "" + +#. module: queue_job +#: model:ir.model.fields,help:queue_job.field_queue_job_function__allow_commit +msgid "" +"Allows the job to commit transactions during execution. Under the hood, this " +"executes the job in a new database cursor, which incurs an overhead as it " +"requires an extra connection to the database. " +msgstr "" + #. module: queue_job #: model:ir.model.fields,field_description:queue_job.field_queue_job__args msgid "Args" @@ -946,13 +959,13 @@ msgstr "UUID" msgid "" "Unexpected format of Related Action for {}.\n" "Example of valid format:\n" -"{{\"enable\": True, \"func_name\": \"related_action_foo\", " -"\"kwargs\" {{\"limit\": 10}}}}" +"{{\"enable\": True, \"func_name\": \"related_action_foo\", \"kwargs\" " +"{{\"limit\": 10}}}}" msgstr "" "Formato inesperado en la acción relacionada con {}.\n" "Ejemplo de un formato válido:\n" -"{{\"enable\": True, \"func_name\": \"related_action_foo\", " -"\"kwargs\" {{\"limit\": 10}}}}" +"{{\"enable\": True, \"func_name\": \"related_action_foo\", \"kwargs\" " +"{{\"limit\": 10}}}}" #. module: queue_job #. odoo-python diff --git a/queue_job/i18n/fr.po b/queue_job/i18n/fr.po index 0a03d545ef..095c69aae6 100644 --- a/queue_job/i18n/fr.po +++ b/queue_job/i18n/fr.po @@ -59,6 +59,19 @@ msgstr "Statut de l’activité" msgid "Activity Type Icon" msgstr "Icône de type d’activité" +#. module: queue_job +#: model:ir.model.fields,field_description:queue_job.field_queue_job_function__allow_commit +msgid "Allow Commit" +msgstr "" + +#. module: queue_job +#: model:ir.model.fields,help:queue_job.field_queue_job_function__allow_commit +msgid "" +"Allows the job to commit transactions during execution. Under the hood, this " +"executes the job in a new database cursor, which incurs an overhead as it " +"requires an extra connection to the database. " +msgstr "" + #. module: queue_job #: model:ir.model.fields,field_description:queue_job.field_queue_job__args msgid "Args" @@ -946,13 +959,13 @@ msgstr "UUID" msgid "" "Unexpected format of Related Action for {}.\n" "Example of valid format:\n" -"{{\"enable\": True, \"func_name\": \"related_action_foo\", " -"\"kwargs\" {{\"limit\": 10}}}}" +"{{\"enable\": True, \"func_name\": \"related_action_foo\", \"kwargs\" " +"{{\"limit\": 10}}}}" msgstr "" "Format inattendu pour l’action rattachée de {}.\n" "Exemple de format valide :\n" -"{{\"enable\": True, \"func_name\": \"related_action_foo\", " -"\"kwargs\" {{\"limit\": 10}}}}" +"{{\"enable\": True, \"func_name\": \"related_action_foo\", \"kwargs\" " +"{{\"limit\": 10}}}}" #. module: queue_job #. odoo-python diff --git a/queue_job/i18n/it.po b/queue_job/i18n/it.po index 5baf58076e..0a45b4f71f 100644 --- a/queue_job/i18n/it.po +++ b/queue_job/i18n/it.po @@ -59,6 +59,19 @@ msgstr "Stato attività" msgid "Activity Type Icon" msgstr "Icona tipo attività" +#. module: queue_job +#: model:ir.model.fields,field_description:queue_job.field_queue_job_function__allow_commit +msgid "Allow Commit" +msgstr "" + +#. module: queue_job +#: model:ir.model.fields,help:queue_job.field_queue_job_function__allow_commit +msgid "" +"Allows the job to commit transactions during execution. Under the hood, this " +"executes the job in a new database cursor, which incurs an overhead as it " +"requires an extra connection to the database. " +msgstr "" + #. module: queue_job #: model:ir.model.fields,field_description:queue_job.field_queue_job__args msgid "Args" @@ -943,13 +956,13 @@ msgstr "UUID" msgid "" "Unexpected format of Related Action for {}.\n" "Example of valid format:\n" -"{{\"enable\": True, \"func_name\": \"related_action_foo\", " -"\"kwargs\" {{\"limit\": 10}}}}" +"{{\"enable\": True, \"func_name\": \"related_action_foo\", \"kwargs\" " +"{{\"limit\": 10}}}}" msgstr "" "Formato inaspettato di azione colegata per {}.\n" "Esempio di formato valido:\n" -"{{\"enable\": True, \"func_name\": \"related_action_foo\", " -"\"kwargs\" {{\"limit\": 10}}}}" +"{{\"enable\": True, \"func_name\": \"related_action_foo\", \"kwargs\" " +"{{\"limit\": 10}}}}" #. module: queue_job #. odoo-python diff --git a/queue_job/i18n/tr.po b/queue_job/i18n/tr.po index c020117adf..f132fea560 100644 --- a/queue_job/i18n/tr.po +++ b/queue_job/i18n/tr.po @@ -59,6 +59,19 @@ msgstr "Aktivite Durumu" msgid "Activity Type Icon" msgstr "Aktivite Türü Simgesi" +#. module: queue_job +#: model:ir.model.fields,field_description:queue_job.field_queue_job_function__allow_commit +msgid "Allow Commit" +msgstr "" + +#. module: queue_job +#: model:ir.model.fields,help:queue_job.field_queue_job_function__allow_commit +msgid "" +"Allows the job to commit transactions during execution. Under the hood, this " +"executes the job in a new database cursor, which incurs an overhead as it " +"requires an extra connection to the database. " +msgstr "" + #. module: queue_job #: model:ir.model.fields,field_description:queue_job.field_queue_job__args msgid "Args" @@ -943,13 +956,13 @@ msgstr "UUID" msgid "" "Unexpected format of Related Action for {}.\n" "Example of valid format:\n" -"{{\"enable\": True, \"func_name\": \"related_action_foo\", " -"\"kwargs\" {{\"limit\": 10}}}}" +"{{\"enable\": True, \"func_name\": \"related_action_foo\", \"kwargs\" " +"{{\"limit\": 10}}}}" msgstr "" "İlgili eylem için beklenmeyen biçim {}.\n" "Doğru biçim örneği:\n" -"{{\"enable\": True, \"func_name\": \"related_action_foo\", " -"\"kwargs\" {{\"limit\": 10}}}}" +"{{\"enable\": True, \"func_name\": \"related_action_foo\", \"kwargs\" " +"{{\"limit\": 10}}}}" #. module: queue_job #. odoo-python diff --git a/queue_job/i18n/zh_CN.po b/queue_job/i18n/zh_CN.po index f75cca8176..aeedd0d03a 100644 --- a/queue_job/i18n/zh_CN.po +++ b/queue_job/i18n/zh_CN.po @@ -56,6 +56,19 @@ msgstr "活动状态" msgid "Activity Type Icon" msgstr "" +#. module: queue_job +#: model:ir.model.fields,field_description:queue_job.field_queue_job_function__allow_commit +msgid "Allow Commit" +msgstr "" + +#. module: queue_job +#: model:ir.model.fields,help:queue_job.field_queue_job_function__allow_commit +msgid "" +"Allows the job to commit transactions during execution. Under the hood, this " +"executes the job in a new database cursor, which incurs an overhead as it " +"requires an extra connection to the database. " +msgstr "" + #. module: queue_job #: model:ir.model.fields,field_description:queue_job.field_queue_job__args msgid "Args" @@ -929,8 +942,8 @@ msgstr "UUID" msgid "" "Unexpected format of Related Action for {}.\n" "Example of valid format:\n" -"{{\"enable\": True, \"func_name\": \"related_action_foo\", " -"\"kwargs\" {{\"limit\": 10}}}}" +"{{\"enable\": True, \"func_name\": \"related_action_foo\", \"kwargs\" " +"{{\"limit\": 10}}}}" msgstr "" #. module: queue_job