Skip to content

fix: do not resume interrupted workflows that are already finished#7435

Open
jwdb wants to merge 1 commit intoelsa-workflows:mainfrom
jwdb:Fix/only-restart-interrupted-running
Open

fix: do not resume interrupted workflows that are already finished#7435
jwdb wants to merge 1 commit intoelsa-workflows:mainfrom
jwdb:Fix/only-restart-interrupted-running

Conversation

@jwdb
Copy link
Copy Markdown

@jwdb jwdb commented May 4, 2026

Purpose

Prevent restarting interrupted but finished workflows that have IsExecuting = 1 but WorkflowStatus = Finished. Currently these end up in a infinite restart cycle.


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

This solves an infinite restart of interrupted workflows that ended up in a semi-invalid state.

Solution

Extend the filter for the restart to ignore finished workflows


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

@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented May 4, 2026

Greptile Summary

This PR fixes an infinite restart loop for workflow instances that have IsExecuting = true but WorkflowStatus = Finished — a semi-invalid state that caused the RestartInterruptedWorkflowsTask to perpetually re-enqueue them. The fix adds a WorkflowStatus = WorkflowStatus.Running condition to the query filter so only genuinely interrupted (not yet finished) workflows are restarted, and a focused integration test is added to verify the behavior.

Confidence Score: 4/5

Safe to merge; the fix is correct and well-tested, with only a minor test robustness concern.

The production change is a single-line addition to a query filter that is clearly correct given the two-value WorkflowStatus enum. The only finding is a P2 test fragility around hardcoded timestamps, which does not affect correctness of the fix.

test/integration/Elsa.Workflows.IntegrationTests/GracefulShutdown/RestartInterruptedWorkflowsTests.cs — hardcoded absolute timestamps may become fragile with mocked clocks.

Important Files Changed

Filename Overview
src/modules/Elsa.Workflows.Runtime/Tasks/RestartInterruptedWorkflowsTask.cs Adds WorkflowStatus = WorkflowStatus.Running to the instance filter, correctly excluding finished workflows from the restart scan.
test/integration/Elsa.Workflows.IntegrationTests/GracefulShutdown/RestartInterruptedWorkflowsTests.cs New integration test validating the filter; uses hardcoded absolute timestamps from April 2026 which could be fragile in environments using a mocked system clock.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[RestartInterruptedWorkflowsTask.ExecuteAsync] --> B[CreateWorkflowInstanceFilter]
    B --> C{Filter conditions}
    C --> D[IsExecuting = true]
    C --> E[BeforeLastUpdated = cutoffTimestamp]
    C --> F["WorkflowStatus = Running NEW"]
    D & E & F --> G[Query WorkflowInstanceStore]
    G --> H{Result set}
    H -->|Running + stale + executing| I[RestartWorkflowAsync]
    H -->|Finished + stale + executing| J[Excluded by new filter]
    I --> K[Workflow resumed]
    J --> L[No restart - bug fixed]
Loading
Prompt To Fix All With AI
Fix the following 1 code review issue. Work through them one at a time, proposing concise fixes.

---

### Issue 1 of 1
test/integration/Elsa.Workflows.IntegrationTests/GracefulShutdown/RestartInterruptedWorkflowsTests.cs:46-47
**Hardcoded timestamps may cause flaky tests with a mocked clock**

The seeded `UpdatedAt`/`CreatedAt` values are pinned to `2026-04-13T12:00:00Z`. The `RestartInterruptedWorkflowsTask` computes its `BeforeLastUpdated` cutoff via `ISystemClock.UtcNow - InactivityThreshold`. If the test service provider registers a mocked or frozen clock set to a time on or before that date (or very close to it), the seeded instances would fall *after* the cutoff and the filter would return zero results — causing the `Assert.Equal(3, ...)` assertion to fail silently. Using a relative offset like `DateTimeOffset.UtcNow.AddDays(-7)` keeps the test robust regardless of clock configuration.

Reviews (1): Last reviewed commit: "Fix: do not resume interrupted workflows..." | Re-trigger Greptile

Comment on lines +46 to +47
for (var i = 0; i < count; i++)
{
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Hardcoded timestamps may cause flaky tests with a mocked clock

The seeded UpdatedAt/CreatedAt values are pinned to 2026-04-13T12:00:00Z. The RestartInterruptedWorkflowsTask computes its BeforeLastUpdated cutoff via ISystemClock.UtcNow - InactivityThreshold. If the test service provider registers a mocked or frozen clock set to a time on or before that date (or very close to it), the seeded instances would fall after the cutoff and the filter would return zero results — causing the Assert.Equal(3, ...) assertion to fail silently. Using a relative offset like DateTimeOffset.UtcNow.AddDays(-7) keeps the test robust regardless of clock configuration.

Prompt To Fix With AI
This is a comment left during a code review.
Path: test/integration/Elsa.Workflows.IntegrationTests/GracefulShutdown/RestartInterruptedWorkflowsTests.cs
Line: 46-47

Comment:
**Hardcoded timestamps may cause flaky tests with a mocked clock**

The seeded `UpdatedAt`/`CreatedAt` values are pinned to `2026-04-13T12:00:00Z`. The `RestartInterruptedWorkflowsTask` computes its `BeforeLastUpdated` cutoff via `ISystemClock.UtcNow - InactivityThreshold`. If the test service provider registers a mocked or frozen clock set to a time on or before that date (or very close to it), the seeded instances would fall *after* the cutoff and the filter would return zero results — causing the `Assert.Equal(3, ...)` assertion to fail silently. Using a relative offset like `DateTimeOffset.UtcNow.AddDays(-7)` keeps the test robust regardless of clock configuration.

How can I resolve this? If you propose a fix, please make it concise.

@jwdb
Copy link
Copy Markdown
Author

jwdb commented May 4, 2026

@dotnet-policy-service agree

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.

1 participant