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

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

  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 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

External Resources