IStimulusDispatcher stack orphaned after #8177 — delete BackgroundStimulusDispatcher / DispatchStimulusCommand
Problem
After #8150 / PR #8177, in-workflow and API async events both route through IWorkflowDispatcher (DispatchTriggerWorkflowsRequest). The parallel IStimulusDispatcher stack appears to have no remaining production callers in elsa-workflows/*, but is still registered, documented, and mirrored by MassTransit (see companion extensions issue).
That is dead accidental complexity left over from the dual-entry era #8149 described — and #8149’s EventPublisher bool-fork evidence is now stale.
Evidence (main @ d339a9c)
What #8177 changed
EventPublisher.PublishAsync(..., asynchronous: true) now calls:
await workflowDispatcher.DispatchAsync(new DispatchTriggerWorkflowsRequest(...), ...);not IStimulusDispatcher. Sync still uses IStimulusSender (correct).
API authenticated event trigger (Events/TriggerAuthenticated) passes asynchronous: true|false into the same IEventPublisher — so API async events also no longer hit BackgroundStimulusDispatcher.
Orphan stack still in DI / tree
| Piece | Status |
|---|---|
IStimulusDispatcher |
Interface + wiki/spec refs only |
BackgroundStimulusDispatcher |
Registered via WorkflowRuntimeFeature.StimulusDispatcher default |
DispatchStimulusRequest / DispatchStimulusCommand / DispatchStimulusCommandHandler |
Only reached from BackgroundStimulusDispatcher |
Unit tests for BackgroundStimulusDispatcher |
Exist; no in-repo production injectors found |
Org-wide code search for IStimulusDispatcher hits only: core contracts/feature/service/docs/specs + extensions MassTransitStimulusDispatcher + gitbook architecture page. No activity, endpoint, or publisher injects it.
Docs drift
doc/wiki/workflow-runtime.md still says API-triggered asynchronous events use the regular background dispatcher / not IStimulusDispatcher for PublishEvent only — partially updated for PublishEvent, but the orphan stack and “API async → background dispatcher” story no longer match code.
Graceful-shutdown specs still name the wrong choke point
specs/002-graceful-shutdown/* still list IStimulusDispatcher as an execution-cycle choke point. If the interface is deleted, those specs need a one-line retarget to IWorkflowDispatcher Trigger/Resume (or whatever remains).
Why it matters
- Maintainability: two async stimulus façades for one job; one has zero callers.
- Correctness risk: MassTransit still wires a separate
StimulusDispatcherbus path (extensions companion) that never seesTransactionalWorkflowDispatcher— inviting future regressions if someone “fixes” a caller by reinjectingIStimulusDispatcher. - Subtractive clarity: #8149 option “delete
IStimulusDispatcher” is no longer a design debate — it is the observed steady state after #8177.
Proposed subtractive direction
- Delete (or quarantine behind obsolete + analyzer) the unused core stack:
IStimulusDispatcher,BackgroundStimulusDispatcher,DispatchStimulusRequest/Response,DispatchStimulusCommand+ handler, feature factoryStimulusDispatcher, and its unit tests. - Keep
IStimulusSender(sync broker) +IWorkflowDispatcherTrigger/Resume (async / outbox path). - Update wiki + graceful-shutdown specs to drop
IStimulusDispatcheras a choke point. - Coordinate with extensions: remove
MassTransitStimulusDispatcher+DispatchStimulusRequestConsumer*(companion issue). - Do not invent a replacement framework. Remaining #8149 work is optional: collapse Trigger vs Resume false dual on
IWorkflowDispatcheronly.
Not a duplicate of
- #8149 — broader dual/triple-entry collapse (EventPublisher fork + Trigger/Resume false dual). This issue is the post-#8177 concrete delete of the now-orphaned leg; prefer close #8149 to “delete done + Trigger/Resume optional leftover” or narrow #8149 after this lands.
- #8150 (closed) / #8177 — durability fix that created this orphan by moving callers onto
IWorkflowDispatcher. - #8167 — outbox Channel delivery bypass (separate).
- #8136 — obsolete inbox DI.
Milestone
Unset — Elsa 3 Issue Triage / Crew Lead place. Soft proposal: Backlog / tech-debt lane beside #8149; do not auto-assign Engineer.
Source: elsa-workflows/elsa-core