CtrlK
BlogDocsLog inGet started
Tessl Logo

clay-reliability-patterns

Implement Clay reliability patterns including circuit breakers, idempotency, and graceful degradation. Use when building fault-tolerant Clay integrations, implementing retry strategies, or adding resilience to production Clay services. Trigger with phrases like "clay reliability", "clay circuit breaker", "clay idempotent", "clay resilience", "clay fallback", "clay bulkhead".

Install with Tessl CLI

npx tessl i github:jeremylongshore/claude-code-plugins-plus-skills --skill clay-reliability-patterns
What are skills?

81

Does it follow best practices?

Validation for skill structure

SKILL.md
Review
Evals

Clay Reliability Patterns

Overview

Production-grade reliability patterns for Clay integrations.

Prerequisites

  • Understanding of circuit breaker pattern
  • opossum or similar library installed
  • Queue infrastructure for DLQ
  • Caching layer for fallbacks

Circuit Breaker

import CircuitBreaker from 'opossum';

const clayBreaker = new CircuitBreaker(
  async (operation: () => Promise<any>) => operation(),
  {
    timeout: 30000,
    errorThresholdPercentage: 50,
    resetTimeout: 30000,
    volumeThreshold: 10,
  }
);

// Events
clayBreaker.on('open', () => {
  console.warn('Clay circuit OPEN - requests failing fast');
  alertOps('Clay circuit breaker opened');
});

clayBreaker.on('halfOpen', () => {
  console.info('Clay circuit HALF-OPEN - testing recovery');
});

clayBreaker.on('close', () => {
  console.info('Clay circuit CLOSED - normal operation');
});

// Usage
async function safeClayCall<T>(fn: () => Promise<T>): Promise<T> {
  return clayBreaker.fire(fn);
}

Idempotency Keys

import { v4 as uuidv4 } from 'uuid';
import crypto from 'crypto';

// Generate deterministic idempotency key from input
function generateIdempotencyKey(
  operation: string,
  params: Record<string, any>
): string {
  const data = JSON.stringify({ operation, params });
  return crypto.createHash('sha256').update(data).digest('hex');
}

// Or use random key with storage
class IdempotencyManager {
  private store: Map<string, { key: string; expiresAt: Date }> = new Map();

  getOrCreate(operationId: string): string {
    const existing = this.store.get(operationId);
    if (existing && existing.expiresAt > new Date()) {
      return existing.key;
    }

    const key = uuidv4();
    this.store.set(operationId, {
      key,
      expiresAt: new Date(Date.now() + 24 * 60 * 60 * 1000),
    });
    return key;
  }
}

Bulkhead Pattern

import PQueue from 'p-queue';

// Separate queues for different operations
const clayQueues = {
  critical: new PQueue({ concurrency: 10 }),
  normal: new PQueue({ concurrency: 5 }),
  bulk: new PQueue({ concurrency: 2 }),
};

async function prioritizedClayCall<T>(
  priority: 'critical' | 'normal' | 'bulk',
  fn: () => Promise<T>
): Promise<T> {
  return clayQueues[priority].add(fn);
}

// Usage
await prioritizedClayCall('critical', () =>
  clayClient.processPayment(order)
);

await prioritizedClayCall('bulk', () =>
  clayClient.syncCatalog(products)
);

Timeout Hierarchy

const TIMEOUT_CONFIG = {
  connect: 5000,      // Initial connection
  request: 30000,     // Standard requests
  upload: 120000,     // File uploads
  longPoll: 300000,   // Webhook long-polling
};

async function timedoutClayCall<T>(
  operation: 'connect' | 'request' | 'upload' | 'longPoll',
  fn: () => Promise<T>
): Promise<T> {
  const timeout = TIMEOUT_CONFIG[operation];

  return Promise.race([
    fn(),
    new Promise<never>((_, reject) =>
      setTimeout(() => reject(new Error(`Clay ${operation} timeout`)), timeout)
    ),
  ]);
}

Graceful Degradation

interface ClayFallback {
  enabled: boolean;
  data: any;
  staleness: 'fresh' | 'stale' | 'very_stale';
}

async function withClayFallback<T>(
  fn: () => Promise<T>,
  fallbackFn: () => Promise<T>
): Promise<{ data: T; fallback: boolean }> {
  try {
    const data = await fn();
    // Update cache for future fallback
    await updateFallbackCache(data);
    return { data, fallback: false };
  } catch (error) {
    console.warn('Clay failed, using fallback:', error.message);
    const data = await fallbackFn();
    return { data, fallback: true };
  }
}

Dead Letter Queue

interface DeadLetterEntry {
  id: string;
  operation: string;
  payload: any;
  error: string;
  attempts: number;
  lastAttempt: Date;
}

class ClayDeadLetterQueue {
  private queue: DeadLetterEntry[] = [];

  add(entry: Omit<DeadLetterEntry, 'id' | 'lastAttempt'>): void {
    this.queue.push({
      ...entry,
      id: uuidv4(),
      lastAttempt: new Date(),
    });
  }

  async processOne(): Promise<boolean> {
    const entry = this.queue.shift();
    if (!entry) return false;

    try {
      await clayClient[entry.operation](entry.payload);
      console.log(`DLQ: Successfully reprocessed ${entry.id}`);
      return true;
    } catch (error) {
      entry.attempts++;
      entry.lastAttempt = new Date();

      if (entry.attempts < 5) {
        this.queue.push(entry);
      } else {
        console.error(`DLQ: Giving up on ${entry.id} after 5 attempts`);
        await alertOnPermanentFailure(entry);
      }
      return false;
    }
  }
}

Health Check with Degraded State

type HealthStatus = 'healthy' | 'degraded' | 'unhealthy';

async function clayHealthCheck(): Promise<{
  status: HealthStatus;
  details: Record<string, any>;
}> {
  const checks = {
    api: await checkApiConnectivity(),
    circuitBreaker: clayBreaker.stats(),
    dlqSize: deadLetterQueue.size(),
  };

  const status: HealthStatus =
    !checks.api.connected ? 'unhealthy' :
    checks.circuitBreaker.state === 'open' ? 'degraded' :
    checks.dlqSize > 100 ? 'degraded' :
    'healthy';

  return { status, details: checks };
}

Instructions

Step 1: Implement Circuit Breaker

Wrap Clay calls with circuit breaker.

Step 2: Add Idempotency Keys

Generate deterministic keys for operations.

Step 3: Configure Bulkheads

Separate queues for different priorities.

Step 4: Set Up Dead Letter Queue

Handle permanent failures gracefully.

Output

  • Circuit breaker protecting Clay calls
  • Idempotency preventing duplicates
  • Bulkhead isolation implemented
  • DLQ for failed operations

Error Handling

IssueCauseSolution
Circuit stays openThreshold too lowAdjust error percentage
Duplicate operationsMissing idempotencyAdd idempotency key
Queue fullRate too highIncrease concurrency
DLQ growingPersistent failuresInvestigate root cause

Examples

Quick Circuit Check

const state = clayBreaker.stats().state;
console.log('Clay circuit:', state);

Resources

  • Circuit Breaker Pattern
  • Opossum Documentation
  • Clay Reliability Guide

Next Steps

For policy enforcement, see clay-policy-guardrails.

Repository
jeremylongshore/claude-code-plugins-plus-skills
Last updated
Created

Is this your skill?

If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.