Skip to content

Commit 10ecfc6

Browse files
committed
Fix DeferError handling when job re-enqueue fails
When a deferred job couldn't be re-enqueued due to concurrency limits, two issues occurred: 1. The pk was left as None after delete() in the rolled-back transaction 2. DeferError was caught by generic Exception handler and logged at ERROR This fix: - Saves and restores self.pk before raising DeferError so convert_to_result works - Adds dedicated DeferError handler with warning-level logging
1 parent 49b362d commit 10ecfc6

1 file changed

Lines changed: 17 additions & 1 deletion

File tree

plain-jobs/plain/jobs/models.py

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -265,6 +265,19 @@ def run(self) -> JobResult:
265265
span.set_status(trace.StatusCode.OK)
266266
return self.convert_to_result(status=JobResultStatuses.SUCCESSFUL)
267267

268+
except DeferError as e:
269+
# Defer failed (e.g., concurrency limit reached during re-enqueue)
270+
# The transaction was rolled back, so the JobProcess still exists in DB.
271+
# The pk was restored in defer() before raising, so we can proceed normally.
272+
logger.warning("Defer failed for %s: %s", self.job_class, e)
273+
span.record_exception(e)
274+
span.set_status(trace.Status(trace.StatusCode.ERROR, str(e)))
275+
span.set_attribute(ERROR_TYPE, type(e).__name__)
276+
return self.convert_to_result(
277+
status=JobResultStatuses.ERRORED,
278+
error=str(e),
279+
)
280+
268281
except Exception as e:
269282
logger.exception(e)
270283
span.record_exception(e)
@@ -294,7 +307,8 @@ def defer(self, *, job: Job, defer_exception: DeferJob) -> JobResult:
294307
)
295308

296309
with transaction.atomic():
297-
# 1. Save JobProcess UUID and delete (releases concurrency slot)
310+
# 1. Save JobProcess state and delete (releases concurrency slot)
311+
saved_pk = self.pk
298312
job_process_uuid = self.uuid
299313
job_request_uuid = self.job_request_uuid
300314
started_at = self.started_at
@@ -312,6 +326,8 @@ def defer(self, *, job: Job, defer_exception: DeferJob) -> JobResult:
312326

313327
# Check if re-enqueue failed
314328
if new_job_request is None:
329+
# Restore pk since transaction will roll back and object still exists
330+
self.pk = saved_pk
315331
raise DeferError(
316332
f"Failed to re-enqueue deferred job {self.job_class}: "
317333
f"concurrency limit reached for key '{self.concurrency_key}'"

0 commit comments

Comments
 (0)