Why this matters more than the other issues
Everything else on my list announces itself. These two do not: the app boots, the dashboard is green, a workflow runs to completion in development - and the guarantee the library exists to provide is gone.
1. Durable messages left on sync
ResumeWorkflowMessage and the four others have no routing by default. With no entry in framework.messenger.routing, they are handled inline on the bus, which means a workflow replays inside the web request that started it. The request ends, the process is recycled, and a suspended execution dies with it - the exact failure the library removes.
I checked, and the bundle never sets a TransportNamesStamp itself (grep TransportNamesStamp vendor/gplanchat/ shows only the profiler middleware reading it), so this is entirely on the application's configuration.
It looks fine while you test it, because a workflow that completes in one pass never has to survive anything.
Check: at compile time, resolve the five message classes against framework.messenger.routing. Fail the build when any of them is unrouted or routed to a sync:// transport. The message writes itself:
Gplanchat\Durable\Transport\ResumeWorkflowMessage is not routed to an asynchronous
transport. A workflow would replay inside the web request that started it and die with the
process. Route it to a Doctrine, AMQP or Redis transport.
2. A lock store that is not shared between processes
SingleResumeLockMiddleware serialises resumes with symfony/lock. The stock Sylius/Symfony default is LOCK_DSN=flock, which is per-container. Two workers in two containers then both hold durable-resume-{executionId} and replay the same journal at the same time.
Nothing complains. You find out when an activity runs twice.
Check: refuse FlockStore and SemaphoreStore when the DBAL bridge is enabled, unless an explicit opt-out is set for single-process development.
The configured lock store is per-process (FlockStore). Two workers could resume the same
execution at once. Use a shared store - doctrine, redis, postgresql - or set
durable.dbal.allow_local_lock: true if you run exactly one worker.
Context
Both bit me on a first install. The second one bit twice: my first fix, LOCK_DSN=doctrine://default, is not a DSN symfony/lock accepts, and the failure surfaced three commands later inside an unrelated fixture load - Unsupported Connection: "doctrine://default" thrown from StoreFactory - with nothing tying it back to durable. A note in the README that the value is a DBAL URL, not a connection alias, would have saved that too.
Why this matters more than the other issues
Everything else on my list announces itself. These two do not: the app boots, the dashboard is green, a workflow runs to completion in development - and the guarantee the library exists to provide is gone.
1. Durable messages left on
syncResumeWorkflowMessageand the four others have no routing by default. With no entry inframework.messenger.routing, they are handled inline on the bus, which means a workflow replays inside the web request that started it. The request ends, the process is recycled, and a suspended execution dies with it - the exact failure the library removes.I checked, and the bundle never sets a
TransportNamesStampitself (grep TransportNamesStamp vendor/gplanchat/shows only the profiler middleware reading it), so this is entirely on the application's configuration.It looks fine while you test it, because a workflow that completes in one pass never has to survive anything.
Check: at compile time, resolve the five message classes against
framework.messenger.routing. Fail the build when any of them is unrouted or routed to async://transport. The message writes itself:2. A lock store that is not shared between processes
SingleResumeLockMiddlewareserialises resumes withsymfony/lock. The stock Sylius/Symfony default isLOCK_DSN=flock, which is per-container. Two workers in two containers then both holddurable-resume-{executionId}and replay the same journal at the same time.Nothing complains. You find out when an activity runs twice.
Check: refuse
FlockStoreandSemaphoreStorewhen the DBAL bridge is enabled, unless an explicit opt-out is set for single-process development.Context
Both bit me on a first install. The second one bit twice: my first fix,
LOCK_DSN=doctrine://default, is not a DSNsymfony/lockaccepts, and the failure surfaced three commands later inside an unrelated fixture load -Unsupported Connection: "doctrine://default"thrown fromStoreFactory- with nothing tying it back to durable. A note in the README that the value is a DBAL URL, not a connection alias, would have saved that too.