Singleton Workflows (feature request)
We'd love if dbos supported singleton workflows. The way I imagine this working is that the workflow can be called with a singleton id (a bit like a dedup id). If there is not a workflow currently running with that id, then it spawns a new workflow. If there is, then it will just attach to that workflow's handle (or you could have two options skip/cancel where skip would be what I just described and cancel would cancel the previous workflow).
Thanks for the request, we'll think about this and what the best interface for it would be!
I would like to know more about the use case... what would the workflow be doing and how would we eliminate any race conditions for the end-user. (The primary race condition I'm thinking of is that the WF has finished doing useful work, but hasn't reported its status yet. There'd be a workflow running, but it would not be picking up any new information to work on.)
We already support workflow IDs, in the sense that the workflow runs to completion once per ID, and if you use that ID again you get a handle to the one that already ran... whether it is currently running or finished last week.
We also have the debouncer (https://docs.dbos.dev/typescript/tutorials/workflow-tutorial#debouncing-workflows) now, which keeps one workflow running per debounce key.
Hey chuck, happy to explain more of our use case.
We have expensive, idempotent operations where multiple callers care about the result of the same work One example from our product is ensuring a livekit room exists for a particular avatar. Ensuring the room exists and waiting for the avatar to join takes a while and we don't want multiple instances of this happening at the same time; but if multiple requests come in to join the same room, we want them all to wait for the one room to finish being created which then returns the room name to them all. Debouncer wouldn't really work because we want the workflow to start immediately on the first request. Workflow ids ensure idempotency but wouldn't work in a case where we do want the ability to respawn the workflow if the room dies.
The cancel mode is a bit more similar to the debouncer except that it starts immediately on the first request. The race condition you mention where a stale workflow wouldn't pick up on new information would be solved by the cancel mode since the new invocation would invalidate the old one and use the new information. The attach mode (the example I gave above) only makes sense for situations where the information is guaranteed not to change for a given deduplication key.
To support the ensure-livekit-room use case, we were originally just using queues with concurrency 1 where the start of the workflow first checks to see if a room has been created and short circuits with that one, but it's just a bit more overhead having to manage the queues and such. We ended up building the singleton pattern I described as an abstraction in our codebase by listening to DBOSQueueDuplicatedError and exposing getDeduplicatedWorkflow through a patch.