Repository navigation
Default queue workers skip repair for tasks with an implicit connection #751
Description
Customer-visible problem
Embedded workflows using the application's default queue connection can remain pending after a transient task-claim failure or lost queue envelope. The normal queue-worker repair loop filters by the resolved connection name, while those durable tasks can store an implicit connection as null.
With QUEUE_CONNECTION=redis, a Laravel worker emits Looping(connectionName: redis, queue: default). TaskWatchdog passes that scope to RequestedTaskScope, which matches connection=redis exactly. A task storing connection=null is dispatched through Redis by default but excluded from this repair scan. The symbolic default scope does include it.
Verified diagnostic
The trusted SQLite handoff from PR #749 reproduced on unchanged published-tag source 2.5.7, commit e9a767b08c426234c25d2969adcb09473e7af56e, with PHP 8.3.35, Laravel 13.35.0, PHPUnit 12.5.38 and the same generated development dependency identities as the original control. The package intentionally does not commit composer.lock.
- Three parents each start four children, each completing one activity, through two real Redis queue workers and an isolated SQLite database.
- The original feature harness disables automatic repair for 600 seconds. Its ordinary 30-second timeout alone does not prove a recovery defect.
- Removing only that V2 suppression still reproduced pending parents with ready, unclaimed tasks and no repair attempt within the timeout. Actual SQLite task claims raised
database is locked. - A further bounded probe confirmed default queue
redis, queue wake enabled, a registered Looping listener and an actual Redis/default worker heartbeat.taskIds(connection: redis, queue: default)selected zero whiletaskIds(connection: default, queue: default)selected the two pending tasks. A forced Redis-scoped pass selected/dispatched zero. A default-scoped pass selected/dispatched both with no repair failure. - One default pass recovered the initial parents, but later child contention required further repair. That run failed a later timeout after 11 assertions. It is partial recovery evidence, not a passing concurrency qualification.
This identifies a scope mismatch. It does not establish indefinite loss under every deployment, qualify full SQLite concurrency, or implicate the version-range correction in #744.
Acceptance
- A worker on the configured default connection repairs overdue durable tasks and missing resume work that inherited that connection, including null/empty/default representations supported by the existing contract.
- Explicit tasks on another connection or queue remain excluded. Preserve comma-separated scope selection and existing explicit/default scope behavior.
- Apply the same effective connection semantics to scoped deadline/timeout scans that use the shared selector.
- Add focused regression checks and verify the original three-parent/twelve-child case with normal repair enabled, exact source/runtime identities, bounded resources and no duplicate activity completion.
- Run normal repository quality and SQL checks, publish the patch and verify affected embedded/pinned consumers. Keep concurrent Rust Server qualification inputs immutable and coordinate its downstream pin.
Priority P1 because this affects ordinary embedded recovery. General product owner implements this independently of Server #325 and coverage #426.
Activity
rmcdaniel commentedon Oct 11, 2026
Implemented in PR #752, merged
82a244cab0f95cb2ebe4592bccbfb5a6aab08c77. Its treef5a8497b4545bbd0ca93f3e59ff8f3c1e2c6ae5aexactly matches the reviewed head. All 11 applicable PR checks pass, with five intentional target-only skips.The final changed-feature MySQL job executes the new lost-envelope recovery case with 14 assertions, completing in 1.813 seconds, alongside the existing parallel-child cases. The actual SQLite candidate and exact old-selector negative control are documented in the PR. The fix changes default connection selection and preserves other queues/connections and existing lease defaults.
Full main qualification 38117371321 is running before 2.5.9 publication. This issue stays open for the published-package regression and affected pinned consumers. The merged remote/local branch is removed. No active diagnostic runtime remains.
rmcdaniel commentedon Oct 11, 2026
Workflow 2.5.9 is published at
82a244cab0f95cb2ebe4592bccbfb5a6aab08c77. Packagist source/dist references and the fresh normal Composer installation match that commit and report runtime release 2.5.9.composer.jsonbyte-identical to the qualified source. The focused real-worker regression runs with those installed source/resource files mounted read-only, with the existing Testbench development harness. On SQLite, PHP 8.3.35, Laravel 13.35.0, one CPU / 1 GiB and unchanged default leases, it passes 14 assertions in 2.769 seconds of test time. The fixture drops the initial envelope and ages its dispatch timestamps to make it overdue. Ordinary worker Looping events repair the original task, complete the original run with one activity attempt and single completion events, and leave no run failure. Container exit is zero with no OOM. The previously retained exact old-selector control stays pending with zero repair.The complete source/publication qualification and its runtime containers, Redis, network, installed dependencies and 309 MiB scratch are now cleaned up. Existing tags and the Rust owner's Server 2.5.18 / Workflow 2.5.8 cohort remain unchanged.
This issue remains open for the Sample App pinned consumer and documentation update, plus coordinated PHP Server adoption after its current release. SDK versions do not need a release for this embedded connection-selection fix.
rmcdaniel commentedon Oct 11, 2026
The next pinned Server consumer is Server #390, preparing Server 2.5.19 with published Workflow 2.5.9. This ordinary PHP update is coordinated with the Rust Server owner after completing its separate Server 2.5.18 release. All other Composer packages retain their exact entries.
Sample App #196 is qualifying both embedded locks. Website #209 passed all four checks and merged, with deployment verification next.
Waterline's Workflow dependency is development-only. Its standalone production image uses the SDK, and embedded applications supply their own Workflow package. No Waterline or SDK release is needed for this connection selection fix. The sample's actual Waterline HTTP and MCP integration qualifies the affected embedded consumer.
rmcdaniel commentedon Oct 11, 2026
Delivered at
c04481db59446a380deb0e9efb22abf1a5326ac0, with the exact qualified tree. Both locks install Workflow 2.5.9 at82a244cab0f95cb2ebe4592bccbfb5a6aab08c77.mainand immutable tagsha-c04481db59446a380deb0e9efb22abf1a5326ac0-run-38120102329-1have the same indexsha256:5d28ba758e169d5d7609d6f0bb1c3a6ad838f08a8307dd1c9ad7fb25d8d439f5. Raw platform manifest/config hashes, architectures and source revision verify.The development image is
durableworkflow/sample-app-devcontaineron Docker Hub andghcr.io/durable-workflow/sample-app-devcontaineron GHCR. The completed branch and temporary checkout are removed. Server and SDK qualification pins retain their selected versions.rmcdaniel commentedon Oct 11, 2026
Workflow 2.5.9 and its pinned consumers are delivered.
The recovery fix is released and available through the documented artifacts. Qualification covers the PHP package and published PHP Server. Rust Server development and managed Cloud adoption follow their separate owning work.