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: ~0msNo acknowledgment. Operation is sent and immediately returns. Use for non-critical data like analytics events or cursor positions.
MEMORY
DefaultLatency: ~1-5msAcknowledged when operation is validated and queued in server memory. This is the default behavior and matches the current “early ACK” system.
APPLIED
Latency: ~5-20msAcknowledged when CRDT merge is complete. Guarantees that subsequent reads will see this write. Use when you need read-after-write consistency.
REPLICATED
Latency: ~20-100msAcknowledged when operation is broadcast to cluster peers. Data survives single-node failure. Use for important data in multi-node deployments.
PERSISTED
Latency: ~50-500msAcknowledged when written to persistent storage. Highest durability guarantee. Use for financial transactions, audit logs, and critical business data.
Basic 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
// 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:
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:
// 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 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.