You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Summary:
Intent:
- Keep final-DLQ reconciliation durable during dependency outages longer than any finite attempt budget.
- Preserve finite retry budgets for primary subscriptions.
Changes:
- Define MaxAttempts zero as unlimited in both direct Nack and visibility-expiry poll paths.
- Configure the shared DLQ subscription for unlimited retries with second-level dead-lettering disabled.
- Verify the orchestrator pipeline and Runway wiring inherit the shared behavior and update the operational docs.
Reproduction:
- A signal or storage dependency remains unavailable for more than 1000 DLQ reconciliation attempts.
- Previously the finite cap was exhausted; because the reconciliation subscription had its own DLQ disabled, MySQL acknowledged the row and advanced past it, losing the reconciliation message.
- The row now remains retryable until reconciliation succeeds or an operator removes it.
---
<sub>Generated by the 🪄 [pr-create](https://sg.uberinternal.com/code.uber.internal/uber-code/devexp-agent-marketplace/-/blob/claude-code/plugins/dev/uber-dev/skills/pr-create/SKILL.md) skill in devexp-agent-marketplace</sub>
Copy file name to clipboardExpand all lines: platform/errs/README.md
+1-1Lines changed: 1 addition & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -85,7 +85,7 @@ One operational consequence worth knowing before relying on any of this: **retry
85
85
### Choosing a processor
86
86
87
87
-**Primary pipeline consumer** → `NewClassifierProcessor(...)`. Controllers' explicit `NewUserError` / `NewDependencyError` wraps must survive so user errors don't get retried, and unclassified backend errors must be inspected by the registered classifiers.
88
-
-**DLQ reconciliation consumer** → `AlwaysRetryableProcessor`. The DLQ is the last stop; any unprocessable message must come back for another attempt rather than silently drop. The DLQ subscription itself runs with a very high `Retry.MaxAttempts` and with its own DLQ disabled, so "always retryable + bounded-but-effectively-infinite attempts" is the convergence guarantee.
88
+
-**DLQ reconciliation consumer** → `AlwaysRetryableProcessor`. The DLQ is the last stop; any unprocessable message must come back for another attempt rather than silently drop. The DLQ subscription itself runs with unlimited attempts (`Retry.MaxAttempts = 0`) and with its own DLQ disabled, so every returned error remains retryable until reconciliation succeeds or an operator removes the message.
Copy file name to clipboardExpand all lines: platform/extension/messagequeue/README.md
+3-1Lines changed: 3 additions & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -53,7 +53,7 @@ type Delivery interface {
53
53
-**Reject** — poison pill, move to DLQ (or ack if DLQ disabled)
54
54
-**ExtendVisibilityTimeout** — extend processing window for long-running work
55
55
56
-
**`Postpone` vs `Nack` vs `ExtendVisibilityTimeout`:**`Nack` is a failure — the message is immediately eligible again, the redelivery counts toward `Retry.MaxAttempts` and eventually trips the DLQ, and later offsets in the partition keep flowing past the nacked message (a failed message must not halt its partition). `Postpone` is a deliberate wait — the redelivery happens after the chosen delay, resets the failure streak (it restarts at attempt 1), and blocks the partition behind it until it redelivers, in order. `ExtendVisibilityTimeout` is neither: the delivery is still being processed and stays in flight.
56
+
**`Postpone` vs `Nack` vs `ExtendVisibilityTimeout`:**`Nack` is a failure — the message is immediately eligible again, the redelivery counts toward `Retry.MaxAttempts` and eventually trips the DLQ when the limit is finite, and later offsets in the partition keep flowing past the nacked message (a failed message must not halt its partition). `Postpone` is a deliberate wait — the redelivery happens after the chosen delay, resets the failure streak (it restarts at attempt 1), and blocks the partition behind it until it redelivers, in order. `ExtendVisibilityTimeout` is neither: the delivery is still being processed and stays in flight.
57
57
58
58
### SubscriptionConfig
59
59
@@ -70,6 +70,8 @@ cfg.DLQ.Enabled = true
70
70
71
71
See `subscription_config.go` for all fields and defaults.
72
72
73
+
`Retry.MaxAttempts` uses zero to mean unlimited attempts. `DLQSubscriptionConfig` selects this mode and disables a second-level DLQ so reconciliation messages remain retryable until they converge or an operator removes them.
0 commit comments