Keep startup workflow binds recoverable - #3172
Conversation
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 5c0f4c6e66
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| "Workflow definition bind commit retry delay must be positive."); | ||
| } | ||
|
|
||
| var remainingDefinitions = GetDefinitionsAfter(definitions, timedOutWorkflowName); |
There was a problem hiding this comment.
Keep the timed-out workflow in the retry set
When an accepted dispatch never commits, GetDefinitionsAfter removes the failed workflow from the background retry set. For a single or last configured workflow this returns an empty list and starts no retry task; the same removal happens on each later timeout, so the host can run indefinitely without materializing that definition. Dispatch admission is explicitly accepted-only, so the timed-out definition must remain pending, with a committed-binding check before redispatch, rather than being treated as complete.
AGENTS.md reference: AGENTS.md:L57-L57
Useful? React with 👍 / 👎.
| catch (WorkflowDefinitionMaterializationException ex) | ||
| when (ex.Code == WorkflowDefinitionMaterializationException.BindNotCommittedCode && | ||
| !cancellationToken.IsCancellationRequested) |
There was a problem hiding this comment.
Recover the bind timeout when the startup token races it
When the host startup token and the private bind timeout are both requested, WaitForCommittedBindAsync now converts the cancellation into BindNotCommitted, but this filter immediately rejects that exception because the startup token is canceled. The exception therefore still escapes StartAsync and aborts host startup in the exact race this change is intended to recover; the added test uses CancellationToken.None and does not exercise this path.
Useful? React with 👍 / 👎.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Summary
Test plan
dotnet test test/Aevatar.Workflow.Host.Api.Tests/Aevatar.Workflow.Host.Api.Tests.csproj --nologo --filter \"FullyQualifiedName~FileBackedWorkflowCatalogAdmissionTests\"dotnet test test/Aevatar.Workflow.Host.Api.Tests/Aevatar.Workflow.Host.Api.Tests.csproj --nologo(after stopping stale local Aevatar host on port 5000)bash tools/ci/workflow_binding_boundary_guard.shbash tools/ci/test_stability_guards.shcould not complete locally: Python 3.12pyexpatfails to load_XML_SetAllocTrackerActivationThreshold; the guard's first two checks passed before the local Python XML parser failure.🤖 Generated with Claude Code