From 3042c6031f7d6b090cca70e7afa148948a84cde5 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/controllers/main.py | 6 ++++++ 1 file changed, 6 insertions(+) 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()