elsa-workflows / elsa-workflows/elsa-core
InvokeWebhookActivities is not Resuming WebhookEventReceived Activities
- Dominant language
- C#
- Stars
- 7.9k
- Forks
- 1.5k
- Avg merge
- 15h 22m
- Merged PRs (30d)
- 114
Description
## Description
TLDR: Resuming WebhookEventReceived activities with the InvokeWebhookActivities notification handler is not possible. This seems like a big oversight, so I'd like to believe I'm just missing something.
The InvokeWebhookActivities does not include any activity instance id (this seems proper), So the stimulus that gets hashed in the StimulusSender is instance-agnostic. This serves well to trigger new workflows, but not to resume them.
The WebhookEventReceived Activity creates a bookmark on ExecuteAsync if it is not the trigger of a workflow. However, this bookmark is created with the default value for includeActivityInstanceId (true), so the hash is instance-specific.
So when the InvokeWebhookActivities calls the stimulus sender, no bookmarkBoundWorkflows are found, and nothing is resumed.
## Steps to Reproduce
To help us identify the issue more quickly, please follow these guidelines:
1. **Detailed Steps**:
- Create a workflow definition with a WebhookEventReceived activity as "Trigger Workflow"
- Have this activity feed into the same type of activity, but without "Trigger Workflow"
2. **Code Snippets**: If the issue involves code (e.g., JavaScript error, server request failure), include the relevant snippets where the issue occurs.
Elsa.Webhooks.Handlers.InvokeWebhookActivities
```
public class InvokeWebhookActivities(IStimulusSender stimulusSender) : INotificationHandler
{
public async Task HandleAsync(WebhookEventReceived notification, CancellationToken cancellationToken)
{
...
var stimulus = new WebhookEventReceivedStimulus(webhookEvent.EventType);
var input = new Dictionary
{
[nameof(WebhookEvent)] = webhookEvent
};
var metadata = new StimulusMetadata
{
Input = input
};
await stimulusSender.SendAsync(fullTypeName, stimulus, metadata, cancellationToken);
}
}
```
Elsa.Workflows.Runtime.StimulusSender.SendAsync
```
public Task SendAsync(string activityTypeName, object stimulus, StimulusMetadata? metadata = null, CancellationToken cancellationToken = default)
{
var stimulusHash = stimulusHasher.Hash(activityTypeName, stimulus, metadata?.ActivityInstanceId);
return SendAsync(stimulusHash, metadata, cancellationToken);
}
```
Elsa.Webhooks.Activities.WebhookEventReceived
```
protected override async ValueTask ExecuteAsync(ActivityExecutionContext context)
{
if (!context.IsTriggerOfWorkflow())
{
context.CreateBookmark(GetStimulus(context.ExpressionExecutionContext), OnResumeAsync);
return;
}
await ExecuteInternalAsync(context);
}
```
Elsa.Workflows.ActivityExecutionContext.CreateBookmark
```
public Bookmark CreateBookmark(
object stimulus,
ExecuteActivityDelegate? callback,
bool includeActivityInstanceId = true,
IDictionary? customProperties = null)
{
return this.CreateBookmark(new CreateBookmarkArgs()
{
Stimulus = stimulus,
Callback = callback,
IncludeActivityInstanceId = includeActivityInstanceId,
Metadata = customProperties
});
}
```
my Webhook Source:
```
new WebhookSource
{
Id = id,
Name = name,
Origin = origin,
EventTypes = resources
.Select(r => r.ToString())
.SelectMany(r => eventTypes
.Select(e => e.ToString())
.Select(e =>
{
string eventType = $"{r.ToLower()}.{e.ToLower()}";
return new WebhookSourceEventType
{
EventType = eventType,
PayloadType = typeof(WebhookPayload),
ActivityBinding = new WebhookActivityBinding
{
TypeName = getWebhookActivityTypeName(name, eventType),
DisplayName = $"{r} {e}",
Description = $"Triggered by the Webhook Event: {r} {e}"
}
};
}))
.ToHashSet()
}
```
3. **Attachments**: using custom webhook sources, so it would be no use exporting my definition here.
4. **Reproduction Rate**: 100%
5. **Video/Screenshots**:
Hashed Stimulus from hitting with webhook endpoint:
My definition is found, and will be executed:
The first activity completes, and the 2nd creates it's bookmark:
The hash for this bookmark is created, and is different from the hash we saw generated from the InvokeWebhookActivities
no bookmarkBoundActivities are found (although, in my eyes, my workflow should be completed by 2 occurrences of that event, not just 1)
## Expected Behavior
I expect my workflow to trigger, complete the first activity, and suspend at the next webhook activity. Then, on a subsequent webhook event recieved of that same event type, the instance should resume and complete.
## Actual Behavior
My workflow triggers, but can never resume. It also seems that it would be completing both activities if the bookmark hash was the same as the trigger hash, which would be incorrect by structure of the workflow.
## Environment
- **Elsa Package Version**: 3.5.0
## Troubleshooting Attempts
I changed the hash of the bookmark in the database such that it matched the hash of the trigger. This caused that bookmark to resume by the InvokeWebhookActivities.
Contributor guide
Assessment
This issue has not been assessed yet.