@@ -606,3 +606,24 @@ heartbeat cleanup.
606606Back up actor tables with the same consistency guarantees as application data.
607607Restoring only instances without their mailboxes/outboxes, or vice versa, can
608608violate application expectations.
609+
610+ ## Interrupted-message recovery
611+
612+ An interrupted first claimed attempt recovers immediately. Recovery after
613+ persisted attempts 2, 3, 4, ... calls ` retry_delay ` with 1, 2, 3, ... . The
614+ callback returns seconds; defaults grow from 1 to 2 to 4 seconds up to 60 seconds.
615+ This uses total claim attempts, including earlier handler failures, not a
616+ separate lease-loss counter. The delay is stored in ready-message availability
617+ when a stale claim is recovered, survives worker replacement, and keeps later
618+ messages behind that message. Other actors can still run. Custom delays,
619+ including zero, remain authoritative.
620+
621+ Lease loss alone does not create a dead letter, even with ` max_attempts: 1 ` .
622+ Handler failures still use the full attempt count for ` max_attempts ` and
623+ ` retry_delay ` . An always-losing message remains pending indefinitely. Observe
624+ ` activation.lost ` (message ID and total attempt count) and impose an application
625+ stopping policy if a hard bound is required. Calling ` request_shutdown ` from
626+ instrumentation stops the worker before its next pass. Ruby uses a separate
627+ renewal thread and waits after lost turns; it does not have the JavaScript
628+ microtask starvation pattern. A handler must still return before its worker
629+ can finish shutting down.
0 commit comments