DocsGuidesWrite Concern

Write Concern

Configure acknowledgment levels for write operations to balance performance vs durability guarantees.

Overview

Write Concern allows you to specify how much confirmation you need before a write operation is considered successful. This is similar to MongoDB’s writeConcern or Kafka’s acks parameter.

Low Latency

Use FIRE_AND_FORGET or MEMORY for real-time features where speed matters more than guaranteed persistence.

High Durability

Use PERSISTED for critical data like financial transactions where you need confirmation that data won’t be lost.

Write Concern Levels

TopGun provides five Write Concern levels, ordered from lowest to highest durability:

FIRE_AND_FORGET

Latency: ~0ms

No acknowledgment. Operation is sent and immediately returns. Use for non-critical data like analytics events or cursor positions.

MEMORY

DefaultLatency: ~1-5ms

Acknowledged when operation is validated and queued in server memory. This is the default behavior and matches the current “early ACK” system.

APPLIED

Latency: ~5-20ms

Acknowledged when CRDT merge is complete. Guarantees that subsequent reads will see this write. Use when you need read-after-write consistency.

REPLICATED

Latency: ~20-100ms

Acknowledged when operation is broadcast to cluster peers. Data survives single-node failure. Use for important data in multi-node deployments.

PERSISTED

Latency: ~50-500ms

Acknowledged when written to persistent storage. Highest durability guarantee. Use for financial transactions, audit logs, and critical business data.

Basic Usage

Basic Write Concern Usage
import { TopGunClient, WriteConcern } from '@topgunbuild/client';

const client = new TopGunClient({ serverUrl: 'wss://your-server.com' });
const todos = client.getMap('todos');

// Default behavior (MEMORY) - fast, early acknowledgment
todos.set('todo-1', { text: 'Buy groceries', done: false });

// With explicit Write Concern for critical data
todos.set('todo-2', { text: 'Pay bills', done: false }, {
  writeConcern: WriteConcern.PERSISTED,
  timeout: 10000  // 10 second timeout
});

Write Concern Comparison

Choosing the Right Level
// FIRE_AND_FORGET - No acknowledgment, fire and forget
// Use for: Metrics, analytics, non-critical logging
await todos.set(id, data, { writeConcern: WriteConcern.FIRE_AND_FORGET });

// MEMORY (default) - Acknowledged when in server memory
// Use for: Most real-time updates, chat messages, cursor positions
await todos.set(id, data, { writeConcern: WriteConcern.MEMORY });

// APPLIED - Acknowledged when CRDT merge is complete
// Use for: Data that needs immediate read-after-write consistency
await todos.set(id, data, { writeConcern: WriteConcern.APPLIED });

// REPLICATED - Acknowledged when broadcast to cluster peers
// Use for: Important data that must survive single-node failure
await todos.set(id, data, { writeConcern: WriteConcern.REPLICATED });

// PERSISTED - Acknowledged when written to storage
// Use for: Financial transactions, audit logs, critical data
await todos.set(id, data, { writeConcern: WriteConcern.PERSISTED });

Handling Write Results

When using Write Concern levels above FIRE_AND_FORGET, you can get detailed feedback about the write operation:

WriteResult Handling
import { WriteConcern, WriteResult } from '@topgunbuild/core';

const result: WriteResult = await todos.setWithAck('payment-123', {
  amount: 100,
  currency: 'USD',
  status: 'pending'
}, {
  writeConcern: WriteConcern.PERSISTED,
  timeout: 5000
});

if (result.success) {
  console.log(`Payment saved at level: ${result.achievedLevel}`);
  console.log(`Latency: ${result.latencyMs}ms`);
} else {
  console.error(`Write failed: ${result.error}`);
  console.log(`Achieved level: ${result.achievedLevel}`);
  // Handle partial success - data might be at APPLIED but not PERSISTED
}

Timeout and Graceful Degradation

Write Concern operations have a configurable timeout. If the timeout expires before reaching the requested level, the operation returns with partial success information:

Timeout Handling
// Graceful degradation on timeout
const result = await todos.setWithAck('critical-data', value, {
  writeConcern: WriteConcern.PERSISTED,
  timeout: 3000  // 3 second timeout
});

if (!result.success && result.achievedLevel !== WriteConcern.FIRE_AND_FORGET) {
  // Partial success - write was accepted but didn't reach PERSISTED
  // achievedLevel tells us how far it got
  if (result.achievedLevel === WriteConcern.REPLICATED) {
    // Data is replicated but not persisted - will be persisted async
    console.log('Data replicated, persistence in progress');
  } else if (result.achievedLevel === WriteConcern.APPLIED) {
    // Data is in CRDT state but not yet replicated
    console.log('Data applied locally, replication pending');
  }
}

Batch Operations

Write Concern can be applied to batch operations:

Batch Write Concern
// Batch operations with Write Concern
const ops = [
  { key: 'user-1', value: { name: 'Alice' } },
  { key: 'user-2', value: { name: 'Bob' } },
  { key: 'user-3', value: { name: 'Charlie' } },
];

// All operations in batch use same Write Concern
const results = await users.batchSet(ops, {
  writeConcern: WriteConcern.REPLICATED,
  timeout: 5000
});

Best Practices

Use the Right Level for Each Use Case

  • • Real-time collaboration (cursor, presence): FIRE_AND_FORGET or MEMORY
  • • Chat messages, notifications: MEMORY
  • • User profile updates: APPLIED
  • • Order placement, payments: PERSISTED

Set Appropriate Timeouts

Higher Write Concern levels take longer. Set timeouts based on your latency requirements and acceptable user wait time. The default is 5 seconds.

Handle Partial Success

Even if a write doesn’t reach the requested level before timeout, it may have been partially processed. Check achievedLevel to understand the actual state.

Backwards Compatibility

Write Concern is fully backwards compatible. Existing code that doesn’t specify a Write Concern level will continue to use MEMORY behavior (early acknowledgment), which matches the previous default behavior.