feat(worker): add taskworker.task.failed log for failed tasks#635
feat(worker): add taskworker.task.failed log for failed tasks#635s-starostin wants to merge 2 commits into
Conversation
| sentry_sdk.capture_exception(retry_error) | ||
| # In this branch, all exceptions should be either | ||
| # captured or silenced. | ||
| if should_capture_error: |
| When err is silenced AND retries are exhausted, neither the synthetic | ||
| NoRetriesRemainingError capture nor the structured taskworker.task.failed | ||
| log fires. The silenced_exceptions opt-out covers both surfaces on the | ||
| retry-exhausted path. |
There was a problem hiding this comment.
I don't think we need this test, the behavior for silenced errors shouldn't be changed.
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 3782285. Configure here.
| # Also emit structured stdout log for retry-exhausted failures. | ||
| # Uses the original err, not the synthetic retry_error, so the log | ||
| # carries the actual exception that exhausted retries. | ||
| _log_task_failed(inflight.activation, err, processing_pool_name) |
There was a problem hiding this comment.
Retry-exhausted log not gated by silenced_exceptions
Medium Severity
On the retry-exhausted path, _log_task_failed is called unconditionally without checking should_capture_error. The PR description explicitly states this path is "gated by task_func.silenced_exceptions," but the code doesn't implement that gating. When a silenced exception exhausts retries, the original exception will now appear in structured logs (and potentially as a Sentry event via LoggingIntegration), defeating the purpose of silenced_exceptions on this path.
Reviewed by Cursor Bugbot for commit 3782285. Configure here.
There was a problem hiding this comment.
Bugbot is right that the PR description is stale, but I think the suggested code change is wrong. Retry-exhausted reporting is intentionally unconditional per #627, so I’ll update the PR description instead of gating _log_task_failed.


Adds a structured
taskworker.task.failedlog event when task execution fails inrun_worker.For non-retriable failure paths, this replaces direct
sentry_sdk.capture_exception(err)calls with:inside the existing
isolation_scopeblocks where they exist. This givesoperators a structured stdout log with the task identity and original exception
details. In environments where the Sentry SDK
LoggingIntegrationcaptureserror logs, the same call also produces the corresponding Sentry event.
The log includes:
task_idtasknamenamespaceprocessing_poolexception_typeexception_messageFailure paths covered
ProcessingDeadlineExceeded, gated bytask_func.report_timeout_errorstask_func.silenced_exceptionsand retry stateOn the retry-exhausted path, the structured log uses the original task exception
(
err) and fires alongside the existing syntheticNoRetriesRemainingErrorcapture. This keeps retry-exhausted failures visible in worker logs in the same
shape as other task failures, while preserving the existing retry-exhaustion
Sentry grouping/fingerprint.
Existing behavior preserved
task_func.report_timeout_errorsopt-out continues to silence both theSentry-reporting path and the new structured worker log on the timeout path
task_func.silenced_exceptionsopt-out continues to silence both surfaces on the general-exception path (non-fexhausted). Retry-exhausted is intentionally unconditional per fix(iswf): Reverts change to reporting logic that silences NoRetriesRemaining exceptions #627.NoRetriesRemainingErrorsynthetic Sentry capture and fingerprint are unchangedis not wrapped in a new
isolation_scopeNote on retry-exhausted reporting
When Sentry SDK
LoggingIntegrationis configured to capture error-level logs(the default), retry-exhausted failures will now produce two Sentry events:
NoRetriesRemainingErrorevent for retry-exhaustionalerting/grouping
taskworker.task.failedThese represent different exception objects and have distinct grouping behavior.
The synthetic event preserves the existing retry-exhaustion signal, while the
original-exception event/log makes the underlying failure visible to operators.
Refs #610