Runtime Coordination Storage
Configure the key-value and distributed-lock providers that Elsa uses for durable outbox records and multi-node workflow coordination.
Elsa has two infrastructure contracts that are easy to confuse:
IKeyValueStore
Small serialized records such as outbox items, instance heartbeats, and persisted administrative pauses
In-memory
IDistributedLockProvider
Leases that ensure only one node performs a coordinated operation at a time
Local files under App_Data/locks
These defaults are useful for development and single-host tests. They are not durable or cross-node production infrastructure. A production cluster needs a key-value provider visible to every node and a lock provider that coordinates across every node.
UseDistributedRuntime() does not select a shared lock provider or make the default key-value store durable. Configure both storage boundaries explicitly when more than one host can process the same Elsa deployment.
What uses each contract?
The stores are infrastructure, not user-facing workflow data stores. Their consumers have different failure and durability requirements:
Workflow dispatch outbox
IKeyValueStore and IDistributedLockProvider
Pending dispatch records must survive restarts, and only one processor should claim a tenant-scoped batch at a time. See Workflow dispatch outbox.
Distributed bookmark queue worker
IDistributedLockProvider
Only one node processes the distributed queue at a time; a node that cannot acquire the lock retries locally.
Workflow resumption and trigger indexing
IDistributedLockProvider
Concurrent resume and trigger-indexing operations are serialized across nodes.
Instance heartbeats
IKeyValueStore and IDistributedLockProvider
Every node writes a heartbeat; the monitor takes a lock before finding timed-out nodes.
Administrative pause persistence
IKeyValueStore
PausePersistencePolicy.AcrossReactivations can restore a pause after the host is reactivated.
The key-value store is not a replacement for the workflow definition, instance, bookmark, or execution-log stores. Configure the runtime persistence provider for those stores as well, and point every node at the same logical runtime database or document store.
Choose a key-value provider
The default MemoryKeyValueStore loses its records when the process exits and is local to one process. Select a runtime persistence provider that also registers an IKeyValueStore implementation:
EF Core
EFCoreKeyValueStore
Relational database deployments that already use EF Core runtime persistence
MongoDB
MongoKeyValueStore
Deployments using the MongoDB runtime provider
Dapper
DapperKeyValueStore
Deployments using the Dapper runtime provider
For EF Core, the runtime persistence feature wires the key-value store for you:
Use the matching runtime persistence extension when you use MongoDB or Dapper. Do not register a durable workflow instance store while leaving IKeyValueStore on the in-memory default: outbox records and coordination records would still disappear on restart.
The outbox is marker-gated rather than one atomic transaction across every store. A durable key-value provider improves recovery, but it does not turn a workflow-state commit and an outbox write into a single cross-store transaction. See Workflow dispatch outbox for the delivery and recovery semantics.
Choose a distributed lock provider
The runtime feature exposes a provider factory on UseWorkflowRuntime. The release default is a FileDistributedSynchronizationProvider rooted at App_Data/locks. That coordinates processes that can safely share the same local file system; it does not coordinate independent containers or hosts.
Configure a provider supplied by your infrastructure package. Redis, PostgreSQL, and SQL Server are examples of cross-node providers supported by the release's startup diagnostic. The provider must use the same shared resource namespace and compatible lease/timeout settings on every node.
The following shows the Elsa integration point; the provider construction is intentionally omitted because its type and connection lifecycle depend on the package you choose:
Use the constructor and connection lifecycle recommended by the Redis, PostgreSQL, SQL Server, or cloud-lock package you selected. The important Elsa integration point is runtime.DistributedLockProvider; registering an unrelated provider under a different service key does not replace this feature setting.
For a complete Redis example, see Redis distributed locking. For the broader distributed-hosting checklist, see Distributed hosting.
Development and single-host exceptions
The distributed runtime validates its provider during startup. If it detects the built-in file or no-op provider, it logs a warning because the provider cannot coordinate across application nodes. The warning is useful: do not silence it as a substitute for configuring a shared provider.
For a deliberately single-host development or test deployment, acknowledge the local provider explicitly:
The Elsa Server sample enables this option by default only in development. In production, set it to false and treat any local-provider warning as a configuration defect. A shared network folder is not a substitute for a lock service: file semantics and failure detection may not be consistent across hosts.
Validate a deployment
Before adding a second node, verify all of the following:
Every node uses the same durable runtime persistence provider and logical database or document store.
Every node resolves the same cross-node
IDistributedLockProvider.The lock provider can acquire and release a probe lock from each node.
Outbox, heartbeat, and runtime coordination records remain visible after a restart.
A two-node test exercises concurrent resume, trigger indexing, and outbox processing; inspect logs for local-provider warnings and lock timeouts.
Tenant-aware workloads use the same tenant resolution and shared storage configuration on every node.
Elsa exposes a distributed-lock readiness check when you register readiness checks with includeDistributedLocks: true. Add it to the host's readiness pipeline so a node with an unreachable lock provider is not presented as ready:
For the complete runtime, persistence, and endpoint contract—including the sample's /health/live and /health/ready mappings—see Readiness and Health Checks.
The readiness probe confirms that the configured provider can reach and acquire a probe lock; it does not prove that the provider is configured with the right business-level topology. Keep the two-node concurrency test in your deployment validation as well.
Related guides
Last updated