Files
pos-system/.agent/rules/data-consistency-patterns.md

270 lines
7.4 KiB
Markdown

---
trigger: always_on
---
# Data Consistency Patterns
## When to Use This Skill
Use this skill when:
- Implementing distributed transactions across multiple services
- Handling eventual consistency in microservices
- Implementing Saga patterns for distributed workflows
- Designing compensation strategies for failed transactions
- Implementing idempotent operations
- Managing data synchronization across services
- Handling conflict resolution
- Implementing optimistic locking strategies
- Building event sourcing systems
- Ensuring data integrity in distributed systems
## Core Concepts
### ACID vs BASE
**ACID (Traditional Databases):**
- Atomicity: All or nothing
- Consistency: Data always valid
- Isolation: Concurrent transactions isolated
- Durability: Committed changes persist
**BASE (Distributed Systems):**
- Basic Availability: System available most of the time
- Soft state: State may change over time
- Eventual consistency: Consistency achieved eventually
### Consistency Models
| Model | Description | Use Case |
|-------|-------------|----------|
| **Strong** | All nodes see same data at same time | Financial transactions |
| **Weak** | No guarantees about when consistency occurs | Caching |
| **Eventual** | System becomes consistent over time | Read models, analytics |
| **Causal** | Related operations maintain order | User sessions |
### Distributed Transaction Challenges
- Network partitions
- Service failures
- Clock synchronization
- Partial failures
- Two-Phase Commit (2PC) limitations
## Saga Pattern
### Orchestration vs Choreography
| Approach | Central Control | Resilience | Complexity | Best For |
|----------|-----------------|------------|------------|----------|
| **Orchestration** | Yes (single coordinator) | Lower (SPOF) | Easier to debug | Complex workflows |
| **Choreography** | No (event-driven) | Higher | Harder to trace | Simple flows, loose coupling |
### Saga Execution Flow
```
Execute: Step1 -> Step2 -> Step3 -> Complete
| | |
v v v
Compensate: <- Step2.undo <- Step1.undo (on failure)
```
### Key Saga Interfaces
```typescript
interface SagaStep {
name: string;
execute: () => Promise<any>;
compensate: (context: any) => Promise<void>;
retry?: number;
}
interface SagaContext {
sagaId: string;
steps: SagaStep[];
currentStep: number;
data: Record<string, any>;
status: 'pending' | 'running' | 'completed' | 'compensating' | 'failed';
}
```
See [./references/REFERENCE.md](./references/REFERENCE.md) for full Saga orchestrator implementation.
## Idempotency Pattern
Ensures operations can be safely retried without side effects.
### Key Concepts
- **Idempotency Key**: Unique identifier for each operation
- **Result Storage**: Cache results to return on duplicates
- **TTL**: Time-to-live for idempotency records
### Pattern
```typescript
const key = `${operation}:${userId}:${hash(requestData)}`;
await idempotencyHandler.execute(key, () => operation());
```
See [./references/REFERENCE.md](./references/REFERENCE.md) for full implementation.
## Optimistic Locking
Prevents lost updates in concurrent scenarios using version fields.
### Pattern
```typescript
await prisma.entity.update({
where: { id, version: currentVersion },
data: { ...updates, version: { increment: 1 } }
});
```
### Prisma Schema
```prisma
model Entity {
id String @id @default(cuid())
version Int @default(1)
// ... other fields
}
```
See [./references/REFERENCE.md](./references/REFERENCE.md) for full optimistic locking service.
## CQRS Pattern
Command Query Responsibility Segregation separates read and write operations.
### Architecture
```
Write Path: Command -> Write Model -> Event -> Event Store
Read Path: Query -> Read Model (denormalized, optimized for reads)
```
### Key Benefits
- Optimized read models for query performance
- Independent scaling of read/write operations
- Eventual consistency between models
See [./references/REFERENCE.md](./references/REFERENCE.md) for implementation details.
## Conflict Resolution Strategies
| Strategy | Description | Use Case |
|----------|-------------|----------|
| **Last Write Wins** | Latest timestamp wins | Simple scenarios |
| **First Write Wins** | Earliest timestamp wins | Preserving original data |
| **Merge** | Combine both versions | Non-conflicting fields |
| **Manual** | Store for human review | Critical data conflicts |
## Outbox Pattern
Ensures reliable event publishing by storing events in the same transaction as business data.
### Flow
1. Execute business operation in transaction
2. Store event in outbox table (same transaction)
3. Background processor publishes and marks as sent
See [./references/REFERENCE.md](./references/REFERENCE.md) for implementation.
## Best Practices
### Saga Pattern
- Design compensations for every step
- Make steps idempotent for retries
- Set timeouts for saga execution
- Monitor saga execution and compensation
- Choose orchestration for complex workflows, choreography for simple ones
### Idempotency
- Generate keys from request data
- Store keys with results
- Set appropriate TTL for records
- Regularly clean expired records
### Eventual Consistency
- Accept that consistency is eventual
- Use separate read models for queries
- Define resolution strategies upfront
- Monitor consistency lag
### Optimistic Locking
- Add version fields to entities
- Implement retry with exponential backoff
- Handle conflicts gracefully
- Use for read-heavy workloads
## Common Mistakes
### No Compensation Logic
```typescript
// BAD: No compensation
steps: [{ execute: () => createOrder() }]
// GOOD: Always define compensation
steps: [{
execute: () => createOrder(),
compensate: (ctx) => cancelOrder(ctx.orderId)
}]
```
### Missing Idempotency
```typescript
// BAD: Creates duplicate on retry
await createPayment(orderId);
// GOOD: Idempotent check
const existing = await findPayment(idempotencyKey);
if (existing) return existing;
await createPayment(orderId);
```
### Ignoring Partial Failures
```typescript
// BAD: No error handling
await step1(); await step2(); await step3();
// GOOD: Saga orchestration
await sagaOrchestrator.execute(context);
```
### No Version Field
```prisma
// GOOD: Add version for optimistic locking
model Entity {
version Int @default(1)
}
```
## Quick Reference
| Pattern | Use Case | Complexity |
|---------|----------|------------|
| **Saga (Orchestrated)** | Complex multi-step workflows | High |
| **Saga (Choreography)** | Simple event-driven flows | Medium |
| **Outbox Pattern** | Guaranteed event publishing | Medium |
| **Idempotency** | Retry-safe operations | Low |
| **Optimistic Lock** | Concurrent updates | Low |
| **CQRS** | Read/write optimization | High |
| **Dead Letter Queue** | Failed message handling | Medium |
## Resources
### Internal References
- [Detailed Code Examples](./references/REFERENCE.md) - Full implementations for all patterns
- [Event-Driven Architecture](../event-driven-architecture/SKILL.md) - Event patterns
- [Error Handling Patterns](../error-handling-patterns/SKILL.md) - Error handling
- [Database & Prisma](../database-prisma/SKILL.md) - Database patterns
- [Project Rules](../project-rules/SKILL.md) - GoodGo coding standards
### External Resources
- [Saga Pattern](https://microservices.io/patterns/data/saga.html) - Saga pattern overview
- [Event Sourcing](https://martinfowler.com/eaaDev/EventSourcing.html) - Event sourcing pattern
- [CQRS Pattern](https://martinfowler.com/bliki/CQRS.html) - CQRS pattern