Concurrency and Locking¶
Why locking matters¶
Without locking, simultaneous requests can create race conditions:
- duplicate open invites
- double acceptance/decline transitions
- two moves applied in the same turn
Framework locking model¶
The service layer acquires database locks before delegating runtime mutations:
- pair-level locking for invite creation (same user pair)
- match-level locking for accept/decline/cancel/forfeit/move
Operations are wrapped in DB transactions in service-level mutation methods.
Runtime authoring rules¶
- assume concurrent requests are possible
- rely on locked read + validate + write pattern
- never trust stale frontend state
- re-read persisted state within the mutation path before writing
Recommended mutation pattern¶
- resolve and validate actor
- load locked match row
- validate state transition and payload
- compute deterministic next state
- update match row
- append move row (if applicable)
- return normalized payload
Idempotency guidance¶
Prefer soft-idempotent behavior for retries:
- repeated same action against already-applied state may return current payload
- unauthorized or semantically invalid actions should still throw