Skip to content

22.6 外掛通訊與協作

概述

在複雜的外掛系統中,外掛之間的通訊與協作是實現高階功能的關鍵。本章節將詳細介紹 Claude Code 外掛系統中的各種通訊機制、協作模式和最佳實踐。

插件通信机制

1. 事件总线 (Event Bus)

事件匯流排是外掛間通訊的核心機制,基於釋出-訂閱模式:

bash
    typescript


    /**
     * 事件总线接口
     */
    export interface IEventBus {
      /**
       * 发布事件
       * @param event 事件名称
       * @param data 事件数据
       */
      publish(event: string, data?: any): Promise<void>;

      /**
       * 订阅事件
       * @param event 事件名称
       * @param handler 事件处理函数
       */
      subscribe(event: string, handler: EventHandler): Subscription;

      /**
       * 取消订阅
       * @param subscription 订阅对象
       */
      unsubscribe(subscription: Subscription): void;

      /**
       * 订阅一次性事件
       * @param event 事件名称
       * @param handler 事件处理函数
       */
      once(event: string, handler: EventHandler): Subscription;
    }

### 使用示例

    typescript


    // 插件A发布事件
    context.eventBus.publish('user.created', { id: '123', name: 'John' });

    // 插件B订阅事件
    const subscription = context.eventBus.subscribe('user.created', (data) => {
      console.log('User created:', data);
    });

    // 取消订阅
    subscription.unsubscribe();

### 2\. 消息队列 (Message Queue)

訊息佇列用於非同步通訊和任務排程:

python
    typescript


    /**
     * 消息队列接口
     */
    export interface IMessageQueue {
      /**
       * 发送消息
       * @param queue 队列名称
       * @param message 消息内容
       */
      send(queue: string, message: Message): Promise<MessageId>;

      /**
       * 接收消息
       * @param queue 队列名称
       * @param handler 消息处理函数
       */
      receive(queue: string, handler: MessageHandler): void;

      /**
       * 发送延迟消息
       * @param queue 队列名称
       * @param message 消息内容
       * @param delay 延迟时间(毫秒)
       */
      sendDelayed(queue: string, message: Message, delay: number): Promise<MessageId>;

      /**
       * 发送重试消息
       * @param queue 队列名称
       * @param message 消息内容
       * @param retryOptions 重试选项
       */
      sendWithRetry(queue: string, message: Message, retryOptions: RetryOptions): Promise<MessageId>;
    }

### 使用示例

    typescript


    // 发送任务到队列
    const messageId = await context.messageQueue.send('email.tasks', {
      to: 'user@example.com',
      subject: 'Welcome',
      body: 'Hello from Claude Code'
    });

    // 处理队列消息
    context.messageQueue.receive('email.tasks', async (message) => {
      try {
        await sendEmail(message.data);
        return MessageStatus.SUCCESS;
      } catch (error) {
        return MessageStatus.FAILED;
      }
    });

### 3\. RPC 调用 (Remote Procedure Call)

RPC 允許外掛直接呼叫其他外掛的方法:

bash
    typescript


    /**
     * RPC 客户端接口
     */
    export interface IRPCClient {
      /**
       * 调用远程方法
       * @param service 服务名称
       * @param method 方法名称
       * @param parameters 方法参数
       */
      call(service: string, method: string, parameters?: any[]): Promise<any>;

      /**
       * 调用远程方法(带超时)
       * @param service 服务名称
       * @param method 方法名称
       * @param parameters 方法参数
       * @param timeout 超时时间(毫秒)
       */
      callWithTimeout(service: string, method: string, parameters?: any[], timeout?: number): Promise<any>;

      /**
       * 订阅服务
       * @param service 服务名称
       * @param callback 服务状态变化回调
       */
      subscribeService(service: string, callback: ServiceStatusCallback): void;
    }

### 使用示例

    typescript


    // 插件A提供服务
    context.rpcServer.register('calculator', {
      add: (a, b) => a + b,
      multiply: (a, b) => a * b
    });

    // 插件B调用服务
    const result = await context.rpcClient.call('calculator', 'add', [2, 3]);
    console.log('Result:', result); // 输出: 5

## 插件协作模式

### 1\. 插件依赖管理

外掛可以宣告對其他外掛的依賴:

    typescript


    // package.json
    {
      "name": "my-plugin",
      "version": "1.0.0",
      "dependencies": {
        "auth-plugin": "^1.0.0",
        "storage-plugin": "^2.0.0"
      }
    }

### 2\. 服务发现与注册

外掛可以註冊服務供其他外掛發現和使用:

javascript
    typescript


    // 注册服务
    context.serviceRegistry.register('payment-service', {
      name: 'Stripe Payment',
      version: '1.0.0',
      endpoint: 'stripe-payment',
      metadata: { supportedCurrencies: ['USD', 'EUR', 'CNY'] }
    });

    // 发现服务
    const services = await context.serviceRegistry.discover('payment-service');
    const stripeService = services.find(s => s.metadata.supportedCurrencies.includes('USD'));

### 3\. 插件链 (Plugin Chain)

外掛可以形成鏈式處理流程:

javascript
    typescript


    // 插件A处理请求
    context.eventBus.subscribe('request.received', async (data, next) => {
      data.userId = '123';
      await next(); // 传递给下一个插件
    });

    // 插件B处理请求
    context.eventBus.subscribe('request.received', async (data, next) => {
      data.timestamp = Date.now();
      await next(); // 传递给下一个插件
    });

    // 执行插件链
    const result = await context.pluginChain.execute('request.received', { url: '/api/users' });

## 数据共享与同步

### 1\. 分布式缓存

外掛可以使用分散式快取共享資料:

javascript
    typescript


    // 设置缓存
    await context.cache.set('user:123', { id: '123', name: 'John' }, { ttl: 3600 });

    // 获取缓存
    const user = await context.cache.get('user:123');

    // 删除缓存
    await context.cache.delete('user:123');

    // 批量操作
    await context.cache.multi()
      .set('user:123', user1)
      .set('user:456', user2)
      .expire('user:123', 3600)
      .exec();

### 2\. 分布式锁

外掛可以使用分散式鎖確保資料一致性:

javascript
    typescript


    // 获取锁
    const lock = await context.lock.acquire('resource:lock', { ttl: 30000 });

    try {
      // 执行临界区操作
      await updateResource();
    } finally {
      // 释放锁
      await lock.release();
    }

### 3\. 数据同步

外掛可以使用資料同步機制保持資料一致性:

python
    typescript


    // 监听数据变化
    context.dataSync.watch('users', async (change) => {
      if (change.type === 'create') {
        await sendWelcomeEmail(change.data);
      } else if (change.type === 'update') {
        await updateUserCache(change.data);
      }
    });

    // 同步数据
    await context.dataSync.sync('users', {
      from: '2024-01-01',
      to: '2024-01-31'
    });

## 事务处理

### 1\. 分布式事务

外掛可以參與分散式事務:

javascript
    typescript


    // 开始事务
    const transaction = await context.transactionManager.begin();

    try {
      // 执行多个操作
      await pluginA.createUser(transaction, userData);
      await pluginB.createOrder(transaction, orderData);
      await pluginC.sendNotification(transaction, notificationData);

      // 提交事务
      await transaction.commit();
    } catch (error) {
      // 回滚事务
      await transaction.rollback();
      throw error;
    }

### 2\. 两阶段提交

外掛可以實現兩階段提交協議:

javascript
    typescript


    // 第一阶段:准备
    const participants = [pluginA, pluginB, pluginC];
    const prepareResults = await Promise.all(
      participants.map(p => p.prepare(transaction))
    );

    // 检查准备结果
    if (prepareResults.every(r => r.status === 'prepared')) {
      // 第二阶段:提交
      await Promise.all(participants.map(p => p.commit(transaction)));
    } else {
      // 第二阶段:回滚
      await Promise.all(participants.map(p => p.rollback(transaction)));
    }

## 错误处理与恢复

### 1\. 错误传播

外掛可以透過事件匯流排傳播錯誤:

javascript
    typescript


    // 插件A抛出错误
    try {
      await riskyOperation();
    } catch (error) {
      context.eventBus.publish('plugin.error', {
        pluginId: 'plugin-a',
        error: error.message,
        stack: error.stack
      });
      throw error;
    }

    // 插件B监听错误
    context.eventBus.subscribe('plugin.error', (errorData) => {
      context.logger.error('Plugin error:', errorData);
      // 执行错误恢复逻辑
    });

### 2\. 熔断机制

外掛可以使用熔斷機制防止級聯失敗:

javascript
    typescript


    // 创建熔断器
    const circuitBreaker = context.circuitBreakerFactory.create('external-service', {
      failureThreshold: 50,
      successThreshold: 10,
      timeout: 5000
    });

    // 使用熔断器
    try {
      const result = await circuitBreaker.execute(() => callExternalService());
      return result;
    } catch (error) {
      if (error.type === 'CircuitOpenError') {
        // 熔断器打开,返回降级结果
        return fallbackResult();
      }
      throw error;
    }

### 3\. 降级策略

外掛可以實現降級策略:

javascript
    typescript


    // 降级策略示例
    async function getUsers() {
      try {
        return await database.query('SELECT * FROM users');
      } catch (error) {
        // 数据库失败,返回缓存数据
        context.logger.warn('Database failed, falling back to cache');
        return cache.get('users:all');
      }
    }

## 性能优化

### 1\. 批量处理

外掛可以批次處理請求提高效能:

javascript
    typescript


    // 批量处理事件
    const batchProcessor = context.batchProcessor.create('user-events', {
      batchSize: 100,
      batchTimeout: 1000
    });

    // 发送事件
    batchProcessor.add({ type: 'created', userId: '123' });
    batchProcessor.add({ type: 'updated', userId: '456' });

    // 处理批量
    batchProcessor.on('batch', async (events) => {
      await database.batchInsert('user_events', events);
    });

### 2\. 异步处理

外掛可以使用非同步處理提高響應性:

javascript
    typescript


    // 异步处理请求
    app.post('/api/users', async (req, res) => {
      // 立即返回响应
      res.status(202).json({ status: 'accepted' });

      // 异步处理任务
      setTimeout(async () => {
        await createUser(req.body);
        await sendWelcomeEmail(req.body.email);
      }, 0);
    });

### 3\. 缓存策略

外掛可以使用多級快取提高效能:

javascript
    typescript


    // 多级缓存
    async function getUser(userId) {
      // 先查本地缓存
      let user = localCache.get(`user:${userId}`);
      if (user) return user;

      // 再查分布式缓存
      user = await distributedCache.get(`user:${userId}`);
      if (user) {
        localCache.set(`user:${userId}`, user, { ttl: 60 });
        return user;
      }

      // 最后查数据库
      user = await database.query('SELECT * FROM users WHERE id = ?', [userId]);
      distributedCache.set(`user:${userId}`, user, { ttl: 3600 });
      localCache.set(`user:${userId}`, user, { ttl: 60 });
      return user;
    }

## 安全考虑

### 1\. 权限控制

外掛可以實現細粒度的許可權控制:

javascript
    typescript


    // 权限检查
    async function deleteUser(userId, requester) {
      const permission = await context.permissionService.check(
        requester.id,
        'user:delete',
        { userId }
      );

      if (!permission.granted) {
        throw new Error('Permission denied');
      }

      await database.query('DELETE FROM users WHERE id = ?', [userId]);
    }

### 2\. 数据加密

外掛可以加密敏感資料:

javascript
    typescript


    // 加密数据
    const encryptedData = await context.encryptionService.encrypt(
      sensitiveData,
      'AES-256-GCM',
      { keyId: 'data-encryption-key' }
    );

    // 解密数据
    const decryptedData = await context.encryptionService.decrypt(
      encryptedData,
      'AES-256-GCM',
      { keyId: 'data-encryption-key' }
    );

### 3\. 审计日志

外掛可以記錄審計日誌:

    typescript


    // 记录审计日志
    context.auditLogger.log({
      action: 'user.created',
      actor: 'system',
      target: userId,
      metadata: { ipAddress: '192.168.1.1', userAgent: 'Claude Code' },
      timestamp: new Date()
    });

## 最佳实践

### 1\. 通信协议设计
  • 使用標準化的事件名稱和訊息格式
  • 定義清晰的版本控制策略
  • 提供詳細的文件和示例

2. 錯誤處理

  • 始終處理非同步操作的錯誤
  • 提供有意義的錯誤資訊
  • 實現適當的重試和降級策略

3. 效能最佳化

  • 批次處理減少系統呼叫
  • 使用快取減少重複計算
  • 非同步處理提高響應性

4. 安全性

  • 驗證所有外部輸入
  • 實施最小許可權原則
  • 加密敏感資料

5. 可觀測性

  • 記錄關鍵操作和事件
  • 監控外掛效能和健康狀況
  • 提供詳細的錯誤資訊

總結

外掛通訊與協作是構建複雜外掛系統的關鍵。透過選擇合適的通訊機制、遵循協作模式和最佳實踐,可以構建出高效、可靠和安全的外掛系統。

下一章將介紹外掛測試與除錯技術,幫助開發者確保外掛質量和穩定性。

基于 MIT 许可发布 | 永久导航