Hi folks,
Trying to implement the following pattern with the help of signalWithStart.
If a workflow with a given ID exists, signal will enqueue the next token to be processed for a given ID in a queue. Workflow method will pop it out in a loop and process. Workflow finishes when queue is empty.
If the workflow with a given ID has already finished, signalWithStart will start the workflow (again with the same ID), send the signal to enqueue the token and execute the workflow method.
I am trying to test this with back to back signalWithStart calls in my test with same workflowId. I am creating a different stub for each signalWithStart call however passing the same workflowOptions to each stub so the ID remains the same.
There seem to be following unexpected things happening
The first signal i.e. the first token is enqueued twice. Tested it many times. Second token is enqueued only once.
I am logging a message at the end of the workflow method. It seems like workflow method is getting executed twice instead of tokens getting enqueued and a single workflow processing the tokens back to back.
But even if there are two executions, the runId seems to be the same across both runs?
So I log in the signal method and log as the workflow method exits. It could be that 2 separate executions are running back to back. But are they expected to share the runId?
Why is my first signal being delivered to the second execution i.e. how come the token I am enqueuing through first signalWithStart getting enqueued again? I checked the code many times and the second signalWithStart should not be enqueuing the first token. Is this some artifact of the test environment?
Please correct me if there are any gaps in my understanding Thank you!
Thanks Maxim. Yes I do see the signal side effect twice. The first token is indeed being processed twice because it was enqueued twice. Yes logging with the workflow logger.
I put a breakpoint in the signal method and see it hit 2 times for the first signal.
Workflow is already completed: COMPLETED
WorkflowExecutionAlreadyCompletedError(message:Workflow is already completed: COMPLETED)
at app//com.uber.cadence.internal.testservice.TestWorkflowMutableStateImpl.checkCompleted(TestWorkflowMutableStateImpl.java:1246)
at app//com.uber.cadence.internal.testservice.TestWorkflowMutableStateImpl.update(TestWorkflowMutableStateImpl.java:231)
at app//com.uber.cadence.internal.testservice.TestWorkflowMutableStateImpl.update(TestWorkflowMutableStateImpl.java:212)
at app//com.uber.cadence.internal.testservice.TestWorkflowMutableStateImpl.signal(TestWorkflowMutableStateImpl.java:1528)
at app//com.uber.cadence.internal.testservice.TestWorkflowService.SignalWithStartWorkflowExecution(TestWorkflowService.java:546)
Could this be happening @maxim ? I am sending another signal while the workflow method is still processing the previous token. Does cadence replay all received signals so far?
If the signal is found in the history twice, then the workflow is expected to process it twice. So it is working as expected. You need to find out why you end up sending two signals to the workflow.
Ok doesn’t look like signalWithStart in test env supports AllowDuplicate ID reuse policy
The ID resue policy applies only no workflows are running. I believe in your case the workflow is running, so it is not relevant.
The ID resue policy applies only no workflows are running. I believe in your case the workflow is running, so it is not relevant.
I can see that the first workflow instance has completed. (I am waiting in the test for a few seconds to make sure). Then when I try to start a new instance of the workflow using signalWithStart it fails with “WorkflowExecutionAlreadyCompletedError”.
In the first case where I call signalWithStart with 2 tokens back to back, they are getting enqueued in the same workflow instance. No matter whether the workflow is already running or completed, I should never encounter “WorkflowExecutionAlreadyCompletedError”, right?
If the signal is found in the history twice, then the workflow is expected to process it twice.
Yes I am sending 2 signals intentionally to test serialized token processing. However I see that the first signal is processed twice, hence a total of 3 signal method invocations are happening (2 for the first token and 1 for the second token). Is the second signal hitting the workflow during the execution of the WF method causing the first one to be replayed?
Thanks @maxim Appreciate your help. Cadence is a phenomenal piece of engineering, however with a steep learning curve
Sorry if I mixed the two issues, both are happening in unit test environment.
First issue where a 2 signalWithStarts are invoked and 3 seen to be processed (first one twice).
Second issue is if I let the first instance of workflow finish and attempt to start a new instance using signalWithStart, it fails with WorkflowExecutionAlreadyCompletedError. I’m wondering if this is an artifact of the TestWorkflowEnvironment
I print a log in the signal method. I see the first token is being enqueued twice. First time when I do signalWithStart with first token, then when I do signalWithStart with token 2 I see both token 1 and token 2 getting enqueued. There is nothing in the signal method but add to the queue and print a log.
Thankfully my workflow method is idempotent so duplicate tokens are ignored.
Workflow id is a UUID. Definitely the same. The stacktrace shows that it finds the previous instance of the workflow in completed state and throws and exception. The ID reuse policy should allow for another instance of workflow to be started here, but doesn’t look test env handles it.