Start by defining the violated invariant, such as “payment is captured once” or “an order can transition from Pending to Confirmed only once.” Add correlation IDs and structured logs around reads, writes, versions, retries, and external calls. Reproduce with concurrent requests in a test that uses the real persistence boundary; a single-threaded unit test rarely exposes the race. The durable fix normally belongs in the database, not only in an in-process lock. Use an atomic conditional update, unique constraint, transaction, or optimistic concurrency token: ```csharp public async Task<bool> ConfirmAsync(Order order, CancellationToken ct) { order.Status = OrderStatus.Confirmed; try { await db.SaveChangesAsync(ct); // RowVersion is checked by EF Core return true; } catch (DbUpdateConcurrencyException) { return false; // Reload and decide whether the operation is already complete } } ``` Also make external operations idempotent by sending a stable operation key. Trace thread-pool metrics, but do not assume every async defect is a threading defect. Finally, verify the fix under repeated parallel load and confirm the stored state, not merely HTTP success responses.
Prince Yadav · · 0 likes