Skip to content

fix: handle disposed scope during workflow instance refresh after Blazor disconnect#770

Draft
Copilot wants to merge 2 commits intomainfrom
copilot/fix-elasticsearch-crash-issue
Draft

fix: handle disposed scope during workflow instance refresh after Blazor disconnect#770
Copilot wants to merge 2 commits intomainfrom
copilot/fix-elasticsearch-crash-issue

Conversation

Copy link
Contributor

Copilot AI commented Mar 3, 2026

Purpose

Prevents intermittent host crashes in Workflow Instance Viewer when a Blazor Server circuit disconnects and a timer callback continues into disposed scoped services (IServiceProvider).
This targets the ObjectDisposedException path reported from activity execution refresh calls.


Scope

Select one primary concern:

  • Bug fix (behavior change)
  • Refactor (no behavior change)
  • Documentation update
  • Formatting / code cleanup
  • Dependency / build update
  • New feature

If this PR includes multiple unrelated concerns, please split it before requesting review.


Description

Problem

A periodic refresh in WorkflowInstanceDesigner can outlive circuit lifetime. After _blazor/disconnect, refresh callbacks may still execute and attempt to resolve/use scoped services via backend API providers, triggering unhandled ObjectDisposedException and process termination.

Solution

  • Targeted guard in refresh path
    • Wrap RefreshSelectedItemAsync body in try/catch (ObjectDisposedException).
  • Fail-safe shutdown of periodic work
    • On disposal exception, stop the refresh timer via StopRefreshActivityStatePeriodically() to prevent repeated callbacks into disposed scope.
  • No functional broadening
    • Keeps behavior unchanged in healthy circuits; only alters disconnect/disposal race handling.

Example change:

try
{
    // existing refresh flow
    SelectedActivityExecutions = await GetActivityExecutionRecordsAsync(LastActivityExecution.ActivityNodeId);
    await InvokeAsync(() =>
    {
        StateHasChanged();
        _activityDetailsTab?.Refresh();
    });
}
catch (ObjectDisposedException)
{
    await StopRefreshActivityStatePeriodically();
}

Verification

Steps:

  1. Open Workflow Instance Viewer for a running instance so periodic activity refresh is active.
  2. Simulate abrupt client disconnect (/_blazor/disconnect) while refresh callbacks are in flight.
  3. Observe server behavior during subsequent timer ticks.

Expected outcome:

  • No unhandled ObjectDisposedException from disposed IServiceProvider.
  • Refresh loop is stopped gracefully for the disconnected circuit.

Screenshots / Recordings (if applicable)

Not applicable (no UI layout/visual changes).


Commit Convention

We recommend using conventional commit prefixes:

  • fix: – Bug fixes (behavior change)
  • feat: – New features
  • refactor: – Code changes without behavior change
  • docs: – Documentation updates
  • chore: – Maintenance, tooling, or dependency updates
  • test: – Test additions or modifications

Clear commit messages make reviews easier and history more meaningful.


Checklist

  • The PR is focused on a single concern
  • Commit messages follow the recommended convention
  • Tests added or updated (if applicable)
  • Documentation updated (if applicable)
  • No unrelated cleanup included
  • All tests pass
Original prompt

This section details on the original issue you should resolve

<issue_title>Elsa Studio 3.5.2 Occasionally Crashes</issue_title>
<issue_description>Hi,

I am using Elsa Studio version 3.5.2. Occasionally, the related service crashes.
When we review the logs, we see the issue shown below. It is most likely caused by a WebSocket disconnection, after which an object that is still being used by the UI is disposed in an uncontrolled manner, leading to the crash.

info: Microsoft.AspNetCore.Routing.EndpointMiddleware[1]
Executed endpoint 'Blazor disconnect'
info: Microsoft.AspNetCore.Hosting.Diagnostics[2]
Request finished HTTP/1.1 POST http://elsastudio-test.xxx.com/_blazor/disconnect - 200 0 - 6.4827ms
info: Microsoft.AspNetCore.Hosting.Diagnostics[1]
Request starting HTTP/1.1 POST http://elsastudio-test.xxxx.com/_blazor/disconnect - multipart/form-data;+boundary=----WebKitFormBoundaryvsvstqw9TgzQPSRp 359
info: Microsoft.AspNetCore.Routing.EndpointMiddleware[0]
Executing endpoint 'Blazor disconnect'
info: Microsoft.AspNetCore.Routing.EndpointMiddleware[1]
Executed endpoint 'Blazor disconnect'
info: Microsoft.AspNetCore.Hosting.Diagnostics[2]
Request finished HTTP/1.1 POST http://elsastudio-test.xxx.com/_blazor/disconnect - 200 0 - 4.2283ms
Unhandled exception. System.ObjectDisposedException: Cannot access a disposed object.
Object name: 'IServiceProvider'.
at Microsoft.Extensions.DependencyInjection.ServiceLookup.ThrowHelper.ThrowObjectDisposedException()
at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService(IServiceProvider provider, Type serviceType)
at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService[T](IServiceProvider provider)
at Elsa.Api.Client.Extensions.DependencyInjectionExtensions.CreateApi[T](IServiceProvider serviceProvider, Uri baseAddress)
at Elsa.Studio.Services.DefaultBackendApiClientProvider.GetApiAsync[T](CancellationToken cancellationToken)
at Elsa.Studio.Workflows.Domain.Services.RemoteActivityExecutionService.ListSummariesAsync(String workflowInstanceId, String activityNodeId, CancellationToken cancellationToken)
at Elsa.Studio.Workflows.Components.WorkflowInstanceViewer.Components.WorkflowInstanceDesigner.GetActivityExecutionRecordsAsync(String activityNodeId)
at Elsa.Studio.Workflows.Components.WorkflowInstanceViewer.Components.WorkflowInstanceDesigner.RefreshSelectedItemAsync(String activityExecutionRecordId)
at Elsa.Studio.Workflows.Components.WorkflowInstanceViewer.Components.WorkflowInstanceDesigner.<>c__DisplayClass124_0.<g__Callback|0>d.MoveNext()
--- End of stack trace from previous location ---
at System.Threading.Tasks.Task.<>c.b__128_1(Object state)
at System.Threading.QueueUserWorkItemCallback.Execute()
at System.Threading.ThreadPoolWorkQueue.Dispatch()
at System.Threading.PortableThreadPool.WorkerThread.WorkerThreadStart()</issue_description>

<agent_instructions>Note: 3.5.2 is quite an older version compared to what lives today in main (which is built as 3.7.0 preview packages). Consult online resources to see if this blazor disconnect issue is a known issue and what potential mitigations are, and if this is applicable to what we have in the main branch.</agent_instructions>

Comments on the Issue (you are @copilot in this section)


💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.

Co-authored-by: sfmskywalker <938393+sfmskywalker@users.noreply.github.com>
Copilot AI changed the title [WIP] Fix occasional crashes in Elsa Studio 3.5.2 fix: handle disposed scope during workflow instance refresh after Blazor disconnect Mar 3, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Elsa Studio 3.5.2 Occasionally Crashes

2 participants