Open frank-lusatia opened 3 weeks ago
Based on the provided context, it appears that there is a race condition between the creation of a bookmark and the retrieval of that bookmark by the workflow service. The Thread.Sleep(2000);
is used as a workaround to ensure that the bookmark is created before the workflow service attempts to retrieve it.
To address this issue, you should ensure that the event publishing and bookmark creation are completed before the workflow service starts looking for bookmarks to resume. This could involve using synchronization mechanisms such as semaphores, mutexes, or other signaling constructs to coordinate between the activity that creates the bookmark and the service that processes the event and resumes the workflow.
Additionally, you may want to review the workflow's design to ensure that the event is not published before the bookmark is created, or to implement a retry mechanism in the workflow service that will keep checking for the bookmark for a certain period before giving up.
If the issue persists, you may need to delve deeper into the Elsa Workflow's internal mechanisms for creating and managing bookmarks, or reach out to the Elsa Workflow community for support.
Since the provided context does not include specific methods or properties to address this race condition directly, the above suggestions are based on general best practices for dealing with concurrency and timing issues in asynchronous systems.
This comment was generated by Glime.
The activity creates the bookmark before publishing the event. The activity asynchronously publishes the event after creating the bookmark. The service asynchronously receives the event published by the activity. The BlockingCollection used in the example is already a sufficient synchronization mechanism.
Your analysis of the issue is spot on. There are several ways to go about this:
IWorkflowInbox
to deliver events, which will keep a copy of the event and automatically resume the bookmark as soon as it is persisted. However, there are issues with this architecture, specifically, the event now has to persist in the system for while, which leads to issues where events are processed multiple times. For this reason, this service will be deprecated as of 3.3.context.Defer(=>)
in your activity. This method accepts a lambda that gets called after bookmarks are actually persisted. The downside of this is that the "real" work to be done now happens during the first commit state only, and not directly as the activity executes. This may or may not be an issue in practice. The Defer method is introduced with 3.3.Given that in typical scenarios, only one, or perhaps a handful, of activities create a bookmark, batching their persistence may be considered a premature optimization that is unnecessary and in fact can invite race conditions under certain circumstances as demonstrated here.
Description
An activity creates a bookmark to be suspended and later resumed. The activity then publishes an event. A service waits for incoming events that are potential responses to previously published events. If an event arrives too early, the service will not find the bookmark that has already been created. As a result, the activity is never resumed.
Steps to Reproduce
Detailed Steps:
If the workflow service retrieves all bookmarks immediately after receiving the incoming event, no bookmarks are found. If the workflow service calls
Thread.Sleep(2000);
(line 136) after receiving the incoming event, the previously created bookmark is found.Code Snippets:
Attachments:
Reproduction Rate: 100 %
Video/Screenshots: see below
Additional Configuration: none
Expected Behavior
A bookmark can be found as soon as it has been created.
Actual Behavior
Whether a bookmark is found is time-dependent (race condition).
Screenshots
Environment
Log Output
none
Troubleshooting Attempts
Additional Context
none
Related Issues
none