7.4 KiB
7.4 KiB
trigger
| 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
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 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
const key = `${operation}:${userId}:${hash(requestData)}`;
await idempotencyHandler.execute(key, () => operation());
See ./references/REFERENCE.md for full implementation.
Optimistic Locking
Prevents lost updates in concurrent scenarios using version fields.
Pattern
await prisma.entity.update({
where: { id, version: currentVersion },
data: { ...updates, version: { increment: 1 } }
});
Prisma Schema
model Entity {
id String @id @default(cuid())
version Int @default(1)
// ... other fields
}
See ./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 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
- Execute business operation in transaction
- Store event in outbox table (same transaction)
- Background processor publishes and marks as sent
See ./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
// BAD: No compensation
steps: [{ execute: () => createOrder() }]
// GOOD: Always define compensation
steps: [{
execute: () => createOrder(),
compensate: (ctx) => cancelOrder(ctx.orderId)
}]
Missing Idempotency
// 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
// BAD: No error handling
await step1(); await step2(); await step3();
// GOOD: Saga orchestration
await sagaOrchestrator.execute(context);
No Version Field
// 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 - Full implementations for all patterns
- Event-Driven Architecture - Event patterns
- Error Handling Patterns - Error handling
- Database & Prisma - Database patterns
- Project Rules - GoodGo coding standards
External Resources
- Saga Pattern - Saga pattern overview
- Event Sourcing - Event sourcing pattern
- CQRS Pattern - CQRS pattern