I tried to search the forum to see if this has already been asked, but I didn’t see any exact matches…apologies if this is a repeat.
What I am wondering is how to prevent any race conditions with the use of .signalWithStart at least when DynamicWorkflows are employed with the java-sdk. I am less clear if this is a problem in other SDKs or not. The scenario I am thinking about is similar to the pattern used for the golang-sdk “Mutex” sample (samples-go/mutex at main · temporalio/samples-go · GitHub) where we have a workflow designed to be started with signalwithstart, and intended to run in a loop until the signal pool is drained, at which time the workflow exits.
Consider the following pattern:
- Client “C1” starts workflow “W” with signalWithStart(“foo”)
- W execution begins on a worker, checks to see if there are any pending messages, and receives “foo” from C1.
- W processes “foo”, and loops back to check if there are more signals. It finds none, so the conditional breaks the loop and starts its journey to exit the execution
- Meanwhile, Client “C2” calls signalWithStart(“bar”), and Temporal sees W is already running so it queues the signal “bar” for delivery to W.
- W completes its exit, and the workflow concludes while leaving “bar” not processed.
I imagine that at least in certain SDKs, like golang, the ReceiveAsync call serves as a type of “delivery confirmation” where Temporal would in fact understand that “bar” was never delivered and do something like start a new W execution, delivering “bar” as the first signal.
However, when using at least the Java SDK DynamicWorkflow and RegisterListener calls, its unclear how one may coordinate to prevent the scenario outlined above from happening. Are there “delivery confirmation” APIs I should be calling to prevent this?