Token导航 LogoToken导航TokenDH.com
研究检索需要联网github未标认证来源可访问许可证需确认审计通过

resilient-storage弹性存储

Agent Skill

resilient-storage 用于查找、检索和筛选相关信息,适合在 Codex、Claude、Cursor、Gemini CLI 中需要根据关键词、任务场景或来源线索快速定位候选结果时使用。可结合来源仓库、安装命令和原始 README 继续核验具体用法。安装前建议确认权限范围、维护状态,以及是否会触发联网、命令执行或文件读写。

总安装

485

周安装

20

GitHub Stars

777

下载量

158
CodexClaudeCursorGemini CLI

安装说明

本站只整理中文说明和来源信息,不托管安装包,也不代用户安装。

GitHub

来源数

2

许可证

unknown

最后核验

2026-05-01

来源状态

来源可访问

安装方式

通过对话安装

复制提示词发给支持本地命令或 Skills 的 AI 助手,先确认命令和权限,再让它执行。

请帮我安装这个 Agent Skill:resilient-storage(弹性存储)
来源仓库:https://github.com/dadbodgeoff/drift
仓库路径:skills/resilient-storage
安装命令:
npx skills add https://github.com/dadbodgeoff/drift --skill resilient-storage
安装前请先检查当前环境是否支持对应 CLI,并向我确认将要执行的命令、安装目录、联网范围和文件读写权限;确认后再执行。

命令行安装

复制命令到本机终端执行。该命令会通过 npx skills 从第三方来源获取 Skill;本站只展示命令,不托管安装包,也不自动执行。

skills.shnpx skills
npx skills add https://github.com/dadbodgeoff/drift --skill resilient-storage

简介

用于查找、检索和筛选相关信息。

  • 适合在 Codex、Claude、Cursor、Gemini CLI 中根据关键词或任务场景快速定位候选结果。
  • 通过 npx skills add 命令从指定 GitHub 仓库安装,需确认权限与联网能力。
  • 建议结合原始 README 核验具体用法,注意维护状态和功能边界。
  • 使用前请检查是否会触发文件读写或命令执行,确保环境安全。

SKILL.md

Resilient Storage Layer

Multi-backend storage with automatic failover. Redis primary, database secondary, memory fallback. Circuit breakers per backend. Health-aware routing.

When to Use This Skill

  • Building systems that can't afford storage downtime
  • Need graceful degradation when Redis or database is unavailable
  • Implementing distributed locks that must work even during partial outages
  • Any caching layer that needs high availability

Core Concepts

The resilient storage layer provides:

  • Multiple storage backends with priority ordering
  • Automatic failover when a backend fails
  • Circuit breakers to prevent cascading failures
  • Health checks to detect and recover from outages
  • Memory fallback that's always available

Architecture:

Backend Selection (FAILOVER | ROUND_ROBIN | PRIORITY)
         │
    ┌────┼────┐
    ▼    ▼    ▼
  Redis  DB  Memory
  (P:1) (P:2) (P:999)
    │    │    │
    └────┴────┘
         │
   Health Monitor

Implementation

TypeScript

export enum StorageBackendType {
  REDIS = 'redis',
  SUPABASE = 'supabase',
  MEMORY = 'memory',
}

export enum BackendHealth {
  HEALTHY = 'healthy',
  DEGRADED = 'degraded',
  UNHEALTHY = 'unhealthy',
}

export interface IStorageBackend {
  name: string;
  type: StorageBackendType;

  initialize(): Promise<void>;
  shutdown(): Promise<void>;
  healthCheck(): Promise<BackendHealth>;

  get(key: string): Promise<string | null>;
  set(key: string, value: string, ttlSeconds?: number): Promise<boolean>;
  delete(key: string): Promise<boolean>;

  acquireLock(name: string, holderId: string, ttlSeconds: number): Promise<LockResult>;
  releaseLock(name: string, holderId: string): Promise<boolean>;
}

interface BackendState {
  backend: IStorageBackend;
  priority: number;
  health: BackendHealth;
  circuitOpen: boolean;
  circuitOpenedAt?: Date;
  consecutiveFailures: number;
}

export class ResilientStorage {
  private backends: BackendState[] = [];
  private healthCheckInterval: NodeJS.Timeout | null = null;

  constructor(
    private config: {
      healthCheckIntervalMs: number;
      circuitBreakerThreshold: number;
      circuitBreakerResetMs: number;
    }
  ) {}

  async initialize(backendConfigs: Array<{
    backend: IStorageBackend;
    priority: number;
    enabled: boolean;
  }>): Promise<void> {
    for (const config of backendConfigs) {
      if (!config.enabled) continue;

      try {
        await config.backend.initialize();
        this.backends.push({
          backend: config.backend,
          priority: config.priority,
          health: BackendHealth.HEALTHY,
          circuitOpen: false,
          consecutiveFailures: 0,
        });
      } catch (error) {
        console.warn(`Failed to initialize ${config.backend.name}:`, error);
      }
    }

    // Always add memory fallback
    if (!this.backends.some(b => b.backend.type === StorageBackendType.MEMORY)) {
      const memoryBackend = new MemoryBackend();
      await memoryBackend.initialize();
      this.backends.push({
        backend: memoryBackend,
        priority: 999,
        health: BackendHealth.HEALTHY,
        circuitOpen: false,
        consecutiveFailures: 0,
      });
    }

    // Sort by priority
    this.backends.sort((a, b) => a.priority - b.priority);

    // Start health checks
    this.healthCheckInterval = setInterval(
      () => this.runHealthChecks(),
      this.config.healthCheckIntervalMs
    );
  }

  private async executeWithFailover<T>(
    operation: string,
    fn: (backend: IStorageBackend) => Promise<T>,
    isSuccess: (result: T) => boolean = () => true
  ): Promise<T> {
    const triedBackends = new Set<string>();

    while (triedBackends.size < this.backends.length) {
      const state = this.selectBackend(triedBackends);
      if (!state) break;

      triedBackends.add(state.backend.name);

      try {
        const result = await fn(state.backend);
        if (isSuccess(result)) {
          this.recordSuccess(state);
          return result;
        }
        this.recordFailure(state);
      } catch (error) {
        console.warn(`${operation} failed on ${state.backend.name}:`, error);
        this.recordFailure(state);
      }
    }

    throw new Error(`All backends failed for: ${operation}`);
  }

  private selectBackend(exclude: Set<string>): BackendState | null {
    const available = this.backends.filter(
      b => !exclude.has(b.backend.name) &&
           b.health !== BackendHealth.UNHEALTHY &&
           !b.circuitOpen
    );

    if (available.length === 0) {
      // Try memory fallback even if excluded
      return this.backends.find(
        b => b.backend.type === StorageBackendType.MEMORY
      ) || null;
    }

    return available[0];
  }

  private recordSuccess(state: BackendState): void {
    state.consecutiveFailures = 0;
    if (state.circuitOpen) {
      state.circuitOpen = false;
      console.log(`Circuit closed for ${state.backend.name}`);
    }
  }

  private recordFailure(state: BackendState): void {
    state.consecutiveFailures++;

    if (state.consecutiveFailures >= this.config.circuitBreakerThreshold) {
      if (!state.circuitOpen) {
        state.circuitOpen = true;
        state.circuitOpenedAt = new Date();
        console.warn(`Circuit opened for ${state.backend.name}`);
      }
    }
  }

  // Public API
  async get(key: string): Promise<string | null> {
    return this.executeWithFailover('get', b => b.get(key));
  }

  async set(key: string, value: string, ttlSeconds?: number): Promise<boolean> {
    return this.executeWithFailover('set', b => b.set(key, value, ttlSeconds), r => r);
  }

  async acquireLock(
    name: string,
    holderId: string,
    ttlSeconds: number
  ): Promise<LockResult> {
    return this.executeWithFailover(
      'acquireLock',
      b => b.acquireLock(name, holderId, ttlSeconds),
      r => r.acquired || !r.error
    );
  }
}

Memory Backend (Fallback)

export class MemoryBackend implements IStorageBackend {
  name = 'memory';
  type = StorageBackendType.MEMORY;

  private store = new Map<string, { value: string; expiresAt?: number }>();
  private locks = new Map<string, { holderId: string; expiresAt: number }>();

  async initialize(): Promise<void> {
    setInterval(() => this.cleanup(), 60000);
  }

  async shutdown(): Promise<void> {
    this.store.clear();
    this.locks.clear();
  }

  async healthCheck(): Promise<BackendHealth> {
    return BackendHealth.HEALTHY; // Memory is always healthy
  }

  async get(key: string): Promise<string | null> {
    const entry = this.store.get(key);
    if (!entry) return null;
    if (entry.expiresAt && Date.now() > entry.expiresAt) {
      this.store.delete(key);
      return null;
    }
    return entry.value;
  }

  async set(key: string, value: string, ttlSeconds?: number): Promise<boolean> {
    this.store.set(key, {
      value,
      expiresAt: ttlSeconds ? Date.now() + ttlSeconds * 1000 : undefined,
    });
    return true;
  }

  async delete(key: string): Promise<boolean> {
    return this.store.delete(key);
  }

  async acquireLock(
    name: string,
    holderId: string,
    ttlSeconds: number
  ): Promise<LockResult> {
    const existing = this.locks.get(name);
    const now = Date.now();

    if (existing && existing.expiresAt > now && existing.holderId !== holderId) {
      return { acquired: false, error: 'Lock held by another process' };
    }

    this.locks.set(name, {
      holderId,
      expiresAt: now + ttlSeconds * 1000,
    });

    return { acquired: true };
  }

  async releaseLock(name: string, holderId: string): Promise<boolean> {
    const lock = this.locks.get(name);
    if (!lock || lock.holderId !== holderId) return false;
    this.locks.delete(name);
    return true;
  }

  private cleanup(): void {
    const now = Date.now();
    for (const [key, entry] of this.store) {
      if (entry.expiresAt && entry.expiresAt < now) {
        this.store.delete(key);
      }
    }
    for (const [name, lock] of this.locks) {
      if (lock.expiresAt < now) {
        this.locks.delete(name);
      }
    }
  }
}

Usage Examples

Initialization

const storage = new ResilientStorage({
  healthCheckIntervalMs: 30000,
  circuitBreakerThreshold: 5,
  circuitBreakerResetMs: 60000,
});

await storage.initialize([
  { backend: new RedisBackend(process.env.REDIS_URL), priority: 1, enabled: true },
  { backend: new SupabaseBackend(), priority: 2, enabled: true },
  { backend: new MemoryBackend(), priority: 999, enabled: true },
]);

// Operations automatically failover
await storage.set('key', 'value', 3600);
const value = await storage.get('key');

// Locks work across backends
const lock = await storage.acquireLock('job:123', 'worker-1', 30);

Health Endpoint

// GET /api/health/storage
export async function GET() {
  const status = storage.getHealthStatus();

  const allHealthy = Object.values(status).every(
    s => s.health === 'healthy' && !s.circuitOpen
  );

  return Response.json({
    status: allHealthy ? 'healthy' : 'degraded',
    activeBackend: storage.getActiveBackend(),
    backends: status,
  }, {
    status: allHealthy ? 200 : 503,
  });
}

Best Practices

  1. Always include memory fallback - it's your last line of defense
  2. Set appropriate circuit breaker thresholds based on your SLAs
  3. Monitor backend switches - frequent switches indicate instability
  4. Use health checks to detect issues before they cause failures
  5. Log all failover events for debugging and alerting

Common Mistakes

  • Not including a memory fallback backend
  • Setting circuit breaker thresholds too low (causes flapping)
  • Forgetting to handle the case where all backends fail
  • Not monitoring health check results
  • Using the same TTL for all backends (memory may need shorter TTLs)

Related Patterns

  • circuit-breaker - Prevent cascading failures
  • distributed-lock - Distributed locking implementation
  • leader-election - Leader election using locks
  • graceful-degradation - Graceful degradation strategies

适合场景

01

研究助手

02

事实核查

03

知识库问答

04

带来源的搜索总结

能力概览

能力 1

组合搜索和大模型调用

能力 2

支持多来源检索和总结

能力 3

强调引用来源和事实核查

能力 4

适合研究型 Agent 流程

安装后应在对应宿主中按原始 README 的触发条件使用;具体调用方式请以来源页面和 README 为准。

平台分布

Codex

33.15%
按下载量换算52

Claude

28.28%
按下载量换算45

Cursor

19.96%
按下载量换算32

Gemini CLI

8.71%
按下载量换算14

安全审计

Gen Agent Trust Hub

通过

Socket

通过

Snyk

通过

权限和风险

需要联网

该 Skill 可能需要联网访问来源站点、仓库或外部 API;具体网络访问范围需要结合源码和 README 复核。

安装前确认

本站仅展示第三方公开信息,不托管安装包,不提供自动安装或运行环境。安装前应自行审查源码、依赖和命令行为。当前只有一个来源,正式发布前建议补源仓库或其他目录站核验。

来源信息

继续浏览同类 Skills