elsa-workflows / elsa-core

A .NET workflows library
https://v3.elsaworkflows.io/
MIT License
5.88k stars 1.06k forks source link

Fix discrepancy in Workflow Instance SignalR Hubs #5232

Closed Huzarensalade closed 4 weeks ago

Huzarensalade commented 4 weeks ago

Whenever i tried to load a suspended workflow-instance in a custom instance-viewer, i would get a 404-exception. This is because the IWorkflowInstanceObserver service cannot find an observer with the specified Id. I found that this is because of the following discrepancy:

in WorkflowInstanceObserverFactory.cs in the Elsa-Studio codebase, the following code is used to get a WorkflowInstanceObserver:

/// <inheritdoc />
public async Task<IWorkflowInstanceObserver> CreateAsync(string workflowInstanceId, CancellationToken cancellationToken = default)
{
    // Only observe the workflow instance if the feature is enabled.
    if (!await _remoteFeatureProvider.IsEnabledAsync("Elsa.RealTimeWorkflowUpdates", cancellationToken))
        return new DisconnectedWorkflowInstanceObserver();

    // Get the SignalR connection.
    var baseUrl = _remoteBackendApiClientProvider.Url;
    var hubUrl = new Uri(baseUrl, "hubs/workflow-instance").ToString();
    var connection = new HubConnectionBuilder()
        .WithUrl(hubUrl, _httpMessageHandlerFactory)            
        .Build();

    var observer = new WorkflowInstanceObserver(connection);
    await connection.StartAsync(cancellationToken);
    await connection.SendAsync("ObserveInstanceAsync", workflowInstanceId, cancellationToken: cancellationToken);

    return observer;
}

Notice how the path used to set var hubUrl is "hubs/workflow-instance".

The endpoint to get the WorkflowInstanceObserver is registered by using .UseWorkflowsSignalRHubs() (from Elsa-Core) in program.cs. This extension-method looks like this:

/// <summary>
/// Adds SignalR hubs for receiving workflow events on the client.
/// </summary>
public static IApplicationBuilder UseWorkflowsSignalRHubs(this IApplicationBuilder app) => app.UseEndpoints(endpoints => endpoints.MapHub<WorkflowInstanceHub>("/elsa/hubs/workflow-instance"));

See how it actually sets the path to "/elsa/hubs/workflow-instance"? Replacing app.UseWorkflowsSignalRHubs() with app.UseEndpoints(endpoints => endpoints.MapHub<WorkflowInstanceHub>("/hubs/workflow-instance")); in program.cs solved the issue.

I'm not sure if this is the right solution, and if this change will impact other Elsa-components, but it is worth suggesting and researching, since the the live reload for the suspended workflow instances is such an awesome feature!

P.S. This change can also be turned around by changing the path in WorkflowInstanceObserverFactory.cs in the Elsa-Studio project, and i'd be happy to create a pull-request there if it is the better solution!

Huzarensalade commented 4 weeks ago

I overlooked the fact that we manually change the endpoint earlier, so this suggestion is irrelevant.