Awesome-claude-code consistency-patterns-knowledge
Consistency Patterns knowledge base. Provides strong vs eventual consistency, idempotency keys, optimistic/pessimistic locking, conflict resolution, and saga compensation patterns for distributed systems audits.
install
source · Clone the upstream repo
git clone https://github.com/dykyi-roman/awesome-claude-code
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/dykyi-roman/awesome-claude-code "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/consistency-patterns-knowledge" ~/.claude/skills/dykyi-roman-awesome-claude-code-consistency-patterns-knowledge && rm -rf "$T"
manifest:
skills/consistency-patterns-knowledge/SKILL.mdsource content
Consistency Patterns Knowledge Base
Quick reference for consistency guarantees, locking strategies, idempotency, and conflict resolution in distributed PHP applications.
Strong vs Eventual Consistency
┌─────────────────────────────────────────────────────────────────────────────┐ │ CONSISTENCY DECISION TREE │ ├─────────────────────────────────────────────────────────────────────────────┤ │ │ │ Is data safety-critical? │ │ (money, inventory) │ │ / \ │ │ YES NO │ │ / \ │ │ Single write Can tolerate │ │ location? stale reads? │ │ / \ / \ │ │ YES NO YES NO │ │ | | | | │ │ ▼ ▼ ▼ ▼ │ │ ┌───────┐ ┌────────┐ ┌────────┐ ┌──────────┐ │ │ │Strong │ │Saga + │ │Eventual│ │Lineariz- │ │ │ │(ACID) │ │Compen- │ │Consist.│ │able │ │ │ │ │ │sation │ │+ TTL │ │Reads │ │ │ └───────┘ └────────┘ └────────┘ └──────────┘ │ │ │ └─────────────────────────────────────────────────────────────────────────────┘
| Property | Strong Consistency | Eventual Consistency |
|---|---|---|
| Guarantee | All reads return latest write | Reads may return stale data temporarily |
| Latency | Higher (synchronous coordination) | Lower (async propagation) |
| Availability | Lower (CAP theorem trade-off) | Higher (tolerates partitions) |
| Scalability | Limited by coordination | Highly scalable |
| Complexity | Simpler app logic, harder infra | Simpler infra, harder app logic |
| Use Cases | Financial transactions, inventory | Social feeds, analytics, caches |
| PHP Pattern | DB transactions, SELECT FOR UPDATE | Event-driven sync, CQRS read models |
Idempotency Keys
Overview
Idempotency ensures that performing the same operation multiple times produces the same result. Critical for payment processing, message handling, and API retries.
| Aspect | Details |
|---|---|
| What | Unique key identifying a specific operation attempt |
| Why | Safe retries, at-least-once delivery semantics, duplicate prevention |
| Format | UUIDv4 or |
| Storage | Redis (fast, TTL) or DB (durable, queryable) |
| TTL | 24-72 hours depending on retry window |
Delivery Guarantees
| Guarantee | Description | Idempotency Needed? |
|---|---|---|
| At-most-once | Fire and forget, may lose messages | No |
| At-least-once | Retries until ACK, may duplicate | Yes |
| Exactly-once | Process exactly once (hard) | Built-in deduplication |
Idempotency Middleware (PSR-15)
<?php declare(strict_types=1); namespace Infrastructure\Http\Middleware; use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestInterface; use Psr\Http\Server\MiddlewareInterface; use Psr\Http\Server\RequestHandlerInterface; final readonly class IdempotencyMiddleware implements MiddlewareInterface { private const string HEADER = 'Idempotency-Key'; public function __construct( private \Redis $redis, private int $ttlSeconds = 86400, ) {} public function process( ServerRequestInterface $request, RequestHandlerInterface $handler, ): ResponseInterface { if ($request->getMethod() === 'GET') { return $handler->handle($request); } $key = $request->getHeaderLine(self::HEADER); if ($key === '') { return $handler->handle($request); } $cacheKey = sprintf('idempotency:%s', $key); $cached = $this->redis->get($cacheKey); if ($cached !== false) { return unserialize($cached, ['allowed_classes' => true]); } $response = $handler->handle($request); $this->redis->setex($cacheKey, $this->ttlSeconds, serialize($response)); return $response; } }
Optimistic Locking
Assumes conflicts are rare. Reads a version, performs work, writes only if version unchanged.
| Component | Description |
|---|---|
| Mechanism | Version column incremented on each update |
| Conflict Detection | in UPDATE |
| On Conflict | Throw exception, retry or return error |
| Best For | Read-heavy workloads, low contention |
| Doctrine | attribute on integer/datetime column |
Doctrine Versioned Entity
<?php declare(strict_types=1); namespace Domain\Model; use Doctrine\ORM\Mapping as ORM; #[ORM\Entity] #[ORM\Table(name: 'products')] final class Product { #[ORM\Id] #[ORM\Column(type: 'string', length: 36)] private string $id; #[ORM\Column(type: 'string', length: 255)] private string $name; #[ORM\Column(type: 'integer')] private int $stock; #[ORM\Version] #[ORM\Column(type: 'integer')] private int $version = 1; public function __construct(string $id, string $name, int $stock) { $this->id = $id; $this->name = $name; $this->stock = $stock; } public function decrementStock(int $quantity): void { if ($this->stock < $quantity) { throw new InsufficientStockException($this->id, $this->stock, $quantity); } $this->stock -= $quantity; } public function getVersion(): int { return $this->version; } }
Handling Optimistic Lock Failures
<?php declare(strict_types=1); namespace Application\UseCase; use Doctrine\ORM\OptimisticLockException; final readonly class DecrementStockUseCase { public function __construct( private ProductRepositoryInterface $repository, private int $maxRetries = 3, ) {} public function execute(string $productId, int $quantity): void { $attempt = 0; while ($attempt < $this->maxRetries) { try { $product = $this->repository->findById($productId); $product->decrementStock($quantity); $this->repository->save($product); return; } catch (OptimisticLockException) { $attempt++; if ($attempt >= $this->maxRetries) { throw new ConcurrencyConflictException($productId); } usleep(random_int(10_000, 50_000)); } } } }
Pessimistic Locking
Assumes conflicts are likely. Acquires a lock before reading, blocks other transactions.
| Lock Type | SQL | Behavior |
|---|---|---|
| Exclusive (FOR UPDATE) | | Blocks reads and writes |
| Shared (FOR SHARE) | | Allows reads, blocks writes |
| NOWAIT | | Fails immediately if locked |
| SKIP LOCKED | | Skips locked rows (queue pattern) |
Deadlock Prevention Rules
- Always acquire locks in consistent order (e.g., by entity ID ascending)
- Use lock timeouts (
)SET innodb_lock_wait_timeout = 5 - Keep transactions short (< 1 second)
- Avoid user interaction within transactions
Conflict Resolution Strategies
| Strategy | Description | Consistency | Complexity |
|---|---|---|---|
| Last Write Wins (LWW) | Latest timestamp wins | Weak | Low |
| First Write Wins | First write preserved, reject subsequent | Strong | Low |
| Merge Function | Custom logic merges conflicting writes | Application-defined | High |
| CRDTs | Conflict-free Replicated Data Types | Eventual (mathematically guaranteed) | Medium |
| Manual Resolution | Human decides on conflict | Strongest | Variable |
CRDT Basics
| CRDT Type | Operations | Example Use |
|---|---|---|
| G-Counter | Increment only | Page view counter |
| PN-Counter | Increment and decrement | Inventory count |
| G-Set | Add only | Tag collection |
| OR-Set | Add and remove | Shopping cart items |
| LWW-Register | Last write wins register | User profile fields |
Saga Compensation vs Distributed Transactions
| Aspect | Distributed Transaction (2PC) | Saga Pattern |
|---|---|---|
| Coordination | Transaction coordinator | Choreography or orchestration |
| Locking | Holds locks across services | No cross-service locks |
| Consistency | Strong (ACID) | Eventual (compensating actions) |
| Availability | Lower (blocking) | Higher (non-blocking) |
| Complexity | Simpler logic, complex infra | Complex logic, simpler infra |
| Failure Handling | Rollback | Compensating transactions |
| Latency | Higher (2-phase commit) | Lower (async steps) |
| Scalability | Poor (locks span services) | Good (independent services) |
Redis Atomic Operations
<?php declare(strict_types=1); namespace Infrastructure\Lock; final readonly class RedisAtomicOperations { public function __construct( private \Redis $redis, ) {} public function acquireLock(string $resource, string $token, int $ttlMs): bool { return $this->redis->set( sprintf('lock:%s', $resource), $token, ['NX', 'PX' => $ttlMs], ) === true; } public function releaseLock(string $resource, string $token): bool { $script = <<<'LUA' if redis.call("get", KEYS[1]) == ARGV[1] then return redis.call("del", KEYS[1]) else return 0 end LUA; return $this->redis->eval( $script, [sprintf('lock:%s', $resource), $token], 1, ) === 1; } public function compareAndSwap(string $key, string $expected, string $newValue, int $ttl): bool { $script = <<<'LUA' if redis.call("get", KEYS[1]) == ARGV[1] then return redis.call("setex", KEYS[1], ARGV[3], ARGV[2]) else return 0 end LUA; return $this->redis->eval( $script, [$key, $expected, $newValue, (string) $ttl], 1, ) !== 0; } }
Common Violations Quick Reference
| Violation | Where to Look | Severity |
|---|---|---|
| No locking on shared mutable state | Repositories, aggregates | Critical |
| Missing idempotency on payment endpoints | API controllers, handlers | Critical |
| Optimistic lock exception swallowed silently | Catch blocks, use cases | Critical |
| Long-running pessimistic locks | Transaction scopes | Warning |
| No retry on optimistic lock failure | Use cases, command handlers | Warning |
| Distributed transaction across services | Service-to-service calls | Critical |
| Missing version field on aggregates | Doctrine entities | Warning |
| Idempotency key without TTL | Redis/cache stores | Warning |
Detection Patterns
# Optimistic locking Grep: "@Version|ORM\\\\Version|version" --glob "**/Entity/**/*.php" Grep: "OptimisticLockException|StaleObjectStateException" --glob "**/*.php" Grep: "LOCK_OPTIMISTIC|LockMode::OPTIMISTIC" --glob "**/*.php" # Pessimistic locking Grep: "FOR UPDATE|FOR SHARE|LOCK_PESSIMISTIC" --glob "**/*.php" Grep: "LockMode::PESSIMISTIC|SKIP LOCKED|NOWAIT" --glob "**/*.php" # Idempotency patterns Grep: "Idempotency|idempotency.key|IdempotencyKey" --glob "**/*.php" Grep: "deduplication|dedup|duplicate.check" --glob "**/*.php" # Distributed locks Grep: "SETNX|NX.*PX|redis.*lock|Lock::acquire" --glob "**/*.php" Grep: "Redlock|RedisLock|LockFactory" --glob "**/*.php" # Saga patterns Grep: "compensat|SagaStep|SagaOrchestrator" --glob "**/*.php" Grep: "CompensatingAction|rollback|undo" --glob "**/Saga/**/*.php" # Consistency indicators Grep: "EventualConsistency|ReadModel|Projection" --glob "**/*.php" Grep: "transaction|beginTransaction|commit|rollback" --glob "**/*.php"
References
For detailed information, load these reference files:
— Optimistic locking, pessimistic locking, distributed locks, Redlock algorithm, Symfony Lock componentreferences/locking-patterns.md
— Idempotency key generation, deduplication store, PSR-15 middleware, delivery guarantees, non-idempotent operationsreferences/idempotency-patterns.md