elsa-workflows / elsa-workflows/elsa-core

Workflow dispatch outbox drops Channel and delivers via mediator Background, bypassing IWorkflowDispatcher

Open
#8,167 0 comments 0 reactions 0 assignees View on GitHub
bug core elsa 3 maintenance prio low tech debt triaged
Dominant language
C#
Stars
7.9k
Forks
1.5k
Avg merge
15h 22m
Merged PRs (30d)
114

Description

## Problem

The workflow-dispatch transactional outbox is hard-wired to **local mediator background commands** and does **not** preserve `DispatchWorkflowOptions.Channel`. That makes the outbox incompatible with channel-aware dispatchers (MassTransit in elsa-extensions) and turns Channel into validate-only theater on the default `BackgroundWorkflowDispatcher` path.

## Evidence

### Channel is a first-class dispatch option

- `DispatchWorkflowOptions.Channel` — sole option field
- `DispatchWorkflow` / `BulkDispatchWorkflows` + API dispatch endpoints set Channel
- `ValidatingWorkflowDispatcher` rejects unknown channels (`DispatchWorkflowResponse.UnknownChannel`)
- MassTransit (`MassTransitWorkflowDispatcher.GetSendEndpointAsync`) formats `queue:elsa-dispatch-workflow-request[-{channel}]`

### Background path ignores Channel

`BackgroundWorkflowDispatcher` accepts `DispatchWorkflowOptions? options` but never reads `options.Channel` — always `CommandStrategy.Background` on the default mediator queue.

### Outbox drops Channel and bypasses IWorkflowDispatcher

- `TransactionalWorkflowDispatcher` enqueues `WorkflowDispatchOutboxItem` with command payloads only — **no Channel / options field** on `WorkflowDispatchOutboxItem`
- `WorkflowDispatchOutboxProcessor.SendAsync` delivers via `ICommandSender.SendAsync(..., CommandStrategy.Background)` — **not** `IWorkflowDispatcher`

So even if MassTransit were wrapped with `TransactionalWorkflowDispatcher`, post-commit delivery would still lose channel routing and MassTransit transport.

## Expected (subtractive)

1. Persist `Channel` (or full `DispatchWorkflowOptions`) on `WorkflowDispatchOutboxItem`.
2. Deliver by calling `IWorkflowDispatcher` **outside** a `WorkflowExecutionContext` (so `TransactionalWorkflowDispatcher` falls through to the inner dispatcher) — or an explicit “immediate/inner” dispatch path — instead of hard-coding mediator Background.
3. Optionally fail closed when Channel is set but the inner dispatcher cannot route channels (avoid silent ignore on Background-only hosts).

Do **not** invent a second outbox or a new channel framework.

## Related

- MassTransit feature currently omits `TransactionalWorkflowDispatcher` entirely (elsa-extensions follow-up)
- #2567 — docs for channels (docs alone will not fix this)
- #4923 (closed) — MassTransit channel endpoints for **direct** dispatch
- #8150 — stimulus/`PublishEvent` outbox bypass (different entry surface)

## Not a duplicate of

- #8150 / #8149 — stimulus entry + PublishEvent durability
- #2567 — documentation request
- #4715 — priority queues

## Milestone

Unset — Elsa 3 Issue Triage / Crew Lead place. Soft: Backlog / tech-debt lane; pair with MassTransit decorator restore. Do not auto-assign Engineer.

Contributor guide

Open the contributing guide

Research direction

Start by tracing TransactionalWorkflowDispatcher, WorkflowDispatchOutboxItem, and WorkflowDispatchOutboxProcessor, then compare their flow with IWorkflowDispatcher and BackgroundWorkflowDispatcher. Verify how DispatchWorkflowOptions.Channel is currently handled and how delivery occurs after commit. Done means the outbox preserves channel information and post-commit delivery reaches the appropriate dispatcher rather than always using mediator Background.

Written by the indexing model from the issue text.

Assessment

Tech stack
csharp
Domain
backend, distributed-systems
Issue type
Bug
Difficulty
5/5
Estimated time
Over a week
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
42/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.