From 6d7d22840f9f30c0535772398cf0c63c9a4450e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miquel=20Ra=C3=AFch?= Date: Fri, 3 Jul 2026 13:42:26 +0200 Subject: [PATCH] [FIX] queue_job: do not enqueue dependent jobs after a retryable postpone When a job's perform() raised a PG serialization error, the runjob controller wrapped it as RetryableJobError and called retry_postpone(), which reassigns job.env to a temporary cursor inside a `with` block and closes it on exit. The handler then fell through to _enqueue_dependent_jobs() -> Job.enqueue_waiting(), running self.env.cr.execute() on that now-closed cursor and raising "psycopg2.OperationalError: Unable to use a closed cursor". A postponed job is not done and must not release its dependent jobs, so return right after the rollback. This also avoids touching the closed cursor. Aligns 12.0 with the upstream 14.0+ behaviour. --- queue_job/__manifest__.py | 2 +- queue_job/controllers/main.py | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/queue_job/__manifest__.py b/queue_job/__manifest__.py index 7b9db132cf..ddc19b44da 100644 --- a/queue_job/__manifest__.py +++ b/queue_job/__manifest__.py @@ -2,7 +2,7 @@ {'name': 'Job Queue', - 'version': '12.0.4.1.0', + 'version': '12.0.4.1.1', 'author': 'Camptocamp,ACSONE SA/NV,Odoo Community Association (OCA)', 'website': 'https://github.com/OCA/queue', 'license': 'LGPL-3', diff --git a/queue_job/controllers/main.py b/queue_job/controllers/main.py index e47461eab0..8cbdb61f46 100644 --- a/queue_job/controllers/main.py +++ b/queue_job/controllers/main.py @@ -148,6 +148,12 @@ def retry_postpone(job, message, seconds=None): # traceback in the logs we should have the traceback when all # retries are exhausted env.cr.rollback() + # A postponed job is not done: it must not release its dependent + # jobs. Returning here also avoids calling _enqueue_dependent_jobs + # with job.env pointing to the now-closed cursor that + # retry_postpone() opened and closed, which would raise + # "Unable to use a closed cursor". + return "" except (FailedJobError, Exception) as orig_exception: buff = StringIO()