Skip to main content

Resilience Layer

Info
Last Updated: 2026-01-08
Built-in Resilience

All Cortex operations include automatic:

  • Rate limiting - Smooths traffic bursts
  • Concurrency control - Respects Convex limits (16 concurrent on free plan)
  • Circuit breaking - Fast-fails when backend is unhealthy
  • Priority queuing - Critical operations execute first

Why It Matters​

Without protection, traffic spikes overwhelm your database:

System Failure
100 Agents Burst
Simultaneous requests
100 Concurrent Queries
All hit database
System Fails
Convex rejects (limit: 16) • Errors cascade

Quick Start​

Zero Configuration​

Resilience is enabled by default with safe settings for Convex Free plan:

import { Cortex } from '@cortexmemory/sdk';

const cortex = new Cortex({
convexUrl: process.env.CONVEX_URL!,
// Resilience enabled automatically
});

// All operations automatically protected
await cortex.memory.remember({...});

Environment Variable​

Set CONVEX_PLAN to auto-configure for your subscription:

# .env
CONVEX_PLAN=free # 16 concurrent (default)
CONVEX_PLAN=professional # 256 concurrent
import { getPresetForPlan } from '@cortexmemory/sdk';

const cortex = new Cortex({
convexUrl: process.env.CONVEX_URL!,
resilience: getPresetForPlan(), // Reads CONVEX_PLAN
});

Configuration Options​

ParameterTypeRequiredDefaultDescription
enabledbooleanNotrueEnable/disable resilience layer
rateLimiter.bucketSizenumberNo100Rate limiter burst capacity
rateLimiter.refillRatenumberNo50Tokens per second (rate limit)
concurrency.maxConcurrentnumberNo20Max simultaneous operations
concurrency.queueSizenumberNo1000Max queued requests
concurrency.timeoutnumberNo30000Request timeout (ms)
circuitBreaker.failureThresholdnumberNo5Failures before circuit opens
circuitBreaker.successThresholdnumberNo2Successes in half-open to close circuit
circuitBreaker.timeoutnumberNo30000Time to wait in open state before half-open (ms)
circuitBreaker.halfOpenMaxnumberNo3Max test requests allowed in half-open state
queue.maxSizeobjectNoSee defaultsMax queue size per priority level (Partial<Record<Priority, number>>)
retry.maxRetriesnumberNo3Maximum number of retry attempts
retry.baseDelayMsnumberNo500Base delay between retries (ms)
retry.maxDelayMsnumberNo10000Maximum delay between retries (ms)
retry.exponentialBasenumberNo2.0Exponential backoff base
retry.jitterbooleanNotrueAdd jitter to prevent thundering herd

Custom Configuration​

const cortex = new Cortex({
convexUrl: process.env.CONVEX_URL!,
resilience: {
enabled: true,

rateLimiter: {
bucketSize: 100, // Max burst
refillRate: 50, // Per second
},

concurrency: {
maxConcurrent: 16, // Convex free limit
queueSize: 1000,
timeout: 30000, // 30s
},

circuitBreaker: {
failureThreshold: 5, // Open after 5 failures
successThreshold: 2, // Close after 2 successes
timeout: 30000, // 30s recovery wait
halfOpenMax: 3, // Max test requests in half-open
},

queue: {
maxSize: { // Per-priority limits
critical: 100,
high: 500,
normal: 1000,
low: 2000,
background: 5000,
},
},

retry: {
maxRetries: 3, // Retry up to 3 times
baseDelayMs: 500, // Start with 0.5s delay
maxDelayMs: 10000, // Cap at 10s
exponentialBase: 2.0, // Double delay each attempt
jitter: true, // Prevent thundering herd
},
},
});

Presets​

Safe defaults for Convex Free/Starter (16 concurrent limit):

import { ResiliencePresets } from '@cortexmemory/sdk';

const cortex = new Cortex({
convexUrl: process.env.CONVEX_URL!,
resilience: ResiliencePresets.default,
});

Settings: Max concurrent: 16, Bucket size: 100, Refill rate: 50/sec, Circuit threshold: 5 failures

Professional Plan Required

batchProcessing and hiveMode presets require Convex Professional plan (256+ concurrent limit). Using with Free plan will cause queuing.


Architecture​

Four protection layers execute in sequence:

Resilience Layer Flow
Request
Incoming request
Rate Limiter
Smooth burst into tokens
Concurrency Limiter
Queue excess requests
Circuit Breaker
Fast-fail if unhealthy
Convex
Backend database
Request flows through four protection layers before reaching Convex

Token Bucket Rate Limiter​

Controls request rate. Bucket starts full, requests consume tokens, tokens refill over time.

Exponential Backoff

When tokens depleted or retries occur, requests wait with exponential backoff:

  • Attempt 1: Immediate (0ms)
  • Attempt 2: ~500ms delay (baseDelayMs)
  • Attempt 3: ~1000ms delay (baseDelayMs × 2)
  • Attempt 4: ~2000ms delay (baseDelayMs × 4)

Default baseDelayMs: 500ms with jitter (random factor 0.5-1.5x) to prevent thundering herd.

Concurrency Limiter​

Controls how many simultaneous requests. Max 16 concurrent on free plan. Excess requests queue by priority.

Priority Queue​

PriorityOperationsQueue Size
criticalCircuit breaker tests100
highUser-facing reads500
normalStandard writes1,000
lowAnalytics2,000
backgroundCleanup5,000

Circuit Breaker​

Prevents cascading failures when backend is unhealthy:

Circuit Breaker State Transitions
CLOSED
Normal operation - requests pass through
OPEN
5 failures detected - fast-fail mode
HALF-OPEN
30s timeout - testing recovery
Circuit breaker transitions between CLOSED, OPEN, and HALF-OPEN states

State Transitions:

  • CLOSED → OPEN: After 5 failures
  • OPEN → HALF-OPEN: After 30s timeout
  • HALF-OPEN → CLOSED: After 2 successes
  • HALF-OPEN → OPEN: On any failure

Monitoring​

const metrics = cortex.getResilienceMetrics();

console.log(metrics);
// {
// rateLimiter: {
// tokensAvailable: 87,
// requestsThrottled: 15,
// avgWaitTimeMs: 234
// },
// concurrency: {
// active: 12,
// waiting: 5,
// maxReached: 16,
// timeouts: 0
// },
// circuitBreaker: {
// state: 'closed',
// failures: 0,
// lastStateChangeAt: 1234567890,
// totalOpens: 0
// },
// queue: {
// total: 5,
// byPriority: {
// critical: 0,
// high: 2,
// normal: 3,
// low: 0,
// background: 0
// },
// processed: 1234,
// dropped: 5,
// oldestRequestAgeMs: 1234
// },
// timestamp: 1234567890
// }

// Alert if circuit opens
if (metrics.circuitBreaker.state === 'open') {
console.error('Backend unhealthy!');
}

// Alert if queue backing up
if (metrics.queue.total > 500) {
console.warn(`Queue depth: ${metrics.queue.total}`);
}

Error Handling​

import { CircuitOpenError, QueueFullError, AcquireTimeoutError } from '@cortexmemory/sdk';

try {
await cortex.memory.remember({...});
} catch (error) {
if (error instanceof CircuitOpenError) {
// Backend unhealthy, circuit tripped
console.error('Service unavailable, try later');
} else if (error instanceof QueueFullError) {
// System overloaded
console.error('Too many requests, try later');
} else if (error instanceof AcquireTimeoutError) {
// Waited too long for permit
console.error('Request timed out');
}
}

Best Practices​

Start with Defaults
// Good: Use defaults tuned for Convex Free plan
const cortex = new Cortex({ convexUrl: process.env.CONVEX_URL! });

// Avoid: Over-customizing without measurement
const cortex = new Cortex({
resilience: { concurrency: { maxConcurrent: 100 } } // Exceeds Convex limits!
});
Match Preset to Plan
// Free/Starter: Use default or realTimeAgent
resilience: ResiliencePresets.default

// Professional: Can use batchProcessing or hiveMode
resilience: ResiliencePresets.batchProcessing
Monitor Circuit State
const cortex = new Cortex({
resilience: {
onCircuitOpen: () => console.error('Circuit OPEN'),
onCircuitClose: () => console.log('Circuit CLOSED'),
},
});

Graceful Shutdown​

// Wait for in-flight requests (with optional timeout)
await cortex.shutdown(30000); // Default: 30s timeout

// In server shutdown handler
process.on('SIGTERM', async () => {
await cortex.shutdown();
process.exit(0);
});

Next Steps​