elsa-workflows / elsa-workflows/elsa-core
Allow application-supplied DbConnection/DbTransaction for EF Core persistence (single-database deployments)
- Dominant language
- C#
- Stars
- 7.9k
- Forks
- 1.5k
- Avg merge
- 15h 22m
- Merged PRs (30d)
- 114
Description
### Summary
When Elsa's EF Core persistence runs against the **same database** as the host
application, there is currently no way to make an application write and an Elsa
runtime write part of **one transaction**. I would like the EF Core persistence
API to optionally accept an application-supplied `DbConnection` (and/or
`DbTransaction`), so a single local transaction can span both.
### Why this is not solvable on the consumer side today
`Elsa.Persistence.EFCore.Common` resolves an `IDbContextFactory` and creates
its own `DbContext` per operation. Scanning the shipped 3.7.1 assembly:
| Symbol | Occurrences |
|---|---|
| `IDbContextFactory` | 1 |
| `CreateDbContextAsync` | 4 |
| `BeginTransaction` | 0 |
| `TransactionScope` | 0 |
So there is no seam for a caller to enlist an existing connection or
transaction. `TransactionScope` is not a viable workaround either: the
application context and Elsa's contexts open separate connections, so the
transaction escalates to MSDTC — which is operationally heavy (and in our case
incompatible with SQL Server Always On plans). It also conflicts with
`EnableRetryOnFailure`, which EF Core refuses to combine with user-initiated
transactions.
### Concrete problem this causes
We keep our own work-item table (task list, SLA, assignment, audit chain) in the
same database as Elsa. On the resume path we:
1. write our work-item state, then
2. let Elsa advance the workflow, then
3. close the work item.
If the process dies between (2) and (3), the decided step and the actual
workflow position diverge. We can *detect* and *repair* this (a 2-minute detection
threshold plus a 2-minute sweep, so roughly a 2-4 minute exposure, and we
separate "stuck" from "flow advanced but item still open"), but we cannot make
it **atomic** — and for a regulated
approval process that residual window is the last item blocking us from calling
the platform enterprise-ready.
### What I'm asking for
An opt-in seam, e.g. one of:
- a delegate/option to supply an existing `DbConnection` (and optionally a
`DbTransaction`) to the EF Core stores, or
- an ambient "unit of work" abstraction the host can open, which the stores
join instead of creating their own context.
Single-database deployments only — no distributed transactions, no 2PC.
### Prior discussion
This was raised before (#1483 / #2459) and the answer was that the persistence
API *could* be opened up for EF Core so a caller can "provide your own
DbConnection and use a single transaction (since you would be using a single
DB)", noting it is "certainly possible but not yet out of the box" and inviting
an issue or PR. This issue is that follow-up.
### Notes on 3.8
I checked the 3.8 release notes first: the transactional outbox there is
marker-gated and explicitly does **not** turn a workflow-state commit and an
outbox write into a single cross-store transaction, so 3.8 does not cover this
case. (Graceful shutdown does help a lot with *planned* restarts — thank you for
that — but not with abrupt termination.)
### Environment
- Elsa 3.7.1, EF Core / SQL Server provider
- Application and Elsa share one database and one connection string
- .NET 9
### Willing to contribute
Yes — happy to work on a PR if you can indicate the shape you'd accept
(connection-supplier delegate vs. unit-of-work abstraction) before I start.
Contributor guide
Research direction
Start in Elsa.Persistence.EFCore.Common by tracing its IDbContextFactory resolution and four CreateDbContextAsync call sites, then review prior discussions #1483 and #2459 for the expected API shape. Done means an opt-in single-database path can join an application-supplied DbConnection or DbTransaction without distributed transactions, with the shared transaction behavior verified.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- csharp
- Domain
- backend-api-design, databases
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 45/100