Asset Concurrency
Summary
Source-backed statement of the Asset Service's concurrency posture: there is no concurrency token, optimistic-concurrency mapping, pessimistic lock, or compare-and-swap anywhere in the source. The only safeguards are lifecycle status re-checks, workflow-callback idempotency, and unique indexes — which reduce but do not guarantee concurrency safety.
Audience
Backend engineers, database reviewers, architects, QA, support, operations, security reviewers, and product owners.
Overview
Concurrent Asset writes are not protected by any database or EF-level concurrency mechanism. The service relies on re-reading the aggregate and re-validating its lifecycle state on each transition, plus idempotent workflow callbacks and unique indexes on identity columns. These narrow, but do not eliminate, the window for lost updates.
Confirmed persistence behavior
Verified absences
- No
RowVersion/Timestamp/ concurrency token and noxminmapping anywhere in the source (verified: noRowVersion,ConcurrencyToken, orIsConcurrencyTokenusage). - No optimistic concurrency — EF Core is not configured to detect concurrent modification on any entity.
- No pessimistic lock — the source issues no row locks (no
FOR UPDATE-style locking). - No compare-and-swap update pattern.
Safeguards that do exist
- Lifecycle status re-check on every transition: each command loads the aggregate and the domain method throws if the asset is not in a valid source state (for example, only
Issuedmay return, onlyRequestedmay approve/reject). A transition attempted against the wrong state fails rather than silently applying. - Workflow-callback idempotency: when a workflow callback arrives and the asset's
Statusis no longerRequested, the callback is acknowledged without re-applying the effect, so duplicate callbacks do not double-process. - Unique indexes:
CompatId(UX_Assets_CompatId) and the outbox / processed-eventEventIdunique indexes prevent duplicate identity or duplicate-event rows at the database.
Why this is not concurrency safety
These mechanisms reduce, but do not guarantee, safety under concurrency:
- Because there is no concurrency token, two requests that both load the aggregate while it is
Availablecan both pass the status re-check and proceed to assign — a classic lost-update / double-assignment window. The status re-check only compares against the state each request read, not against a version stamp validated at write time. - The unique indexes protect identity and event-id uniqueness only; they do not protect lifecycle transitions or the single-assignee invariant.
- Callback idempotency protects against duplicate workflow callbacks, not against concurrent direct commands.
No claim of concurrency safety is made. Interleaved concurrent transitions on the same asset can still race.
Classification
Transitional — lifecycle re-checks, callback idempotency, and unique indexes only; no first-class concurrency control.
Requires confirmation
Whether a concurrency token (for example a row-version column) or a database-level single-assignment constraint should be added to close the double-assignment window requires product and database confirmation.
Related Articles
See Also
Keywords
- Asset persistence
- Concurrency
- Draft database documentation
Source References
microservices/src/asset-service/Domain/Asset/Asset.csmicroservices/src/asset-service/Application/Commands/AssetCommands.csmicroservices/src/asset-service/Infrastructure/AssetDbContext.csmicroservices/src/asset-service/Infrastructure/Migrations/AssetDbContextModelSnapshot.cs
Revision Information
- Status: Draft
- Last reviewed: 2026-07-17
- Review cycle: Quarterly