Skip to content

事件与 payload 参考

本页是 logger 事件和 notify payload 的单一事实源。其它页面通过链接引用此处。

📋 Logger 事件目录

所有治理行为先归一化为标准 LogEvent,再由你配置的 logger 决定去向(默认 console)。标准事件结构见 消息与日志系统

事件名等级触发能力说明
duplicate.triggeredwarnduplicate命中重复请求(ignore / block / reuse)时触发
retry.scheduledinforetry一次失败被判定为可重试,下一次 attempt 已安排等待时触发
retry.exhaustedwarnretryretry 生命周期停止时触发(不只是次数用尽,见下方 reason 字段)
circuitBreaker.blockedwarncircuitBreaker请求被熔断拦截(熔断打开状态)时触发
circuitBreaker.stateChangewarncircuitBreaker熔断状态在 NORMAL / CIRCUIT_BREAKER / HALF_OPEN 间切换时触发
circuitBreaker.halfOpenProbeinfocircuitBreaker半开状态放行试探请求时触发
circuitBreaker.recoveredinfocircuitBreaker半开试探成功、熔断单元恢复到 NORMAL 时触发
requestGuard.internalErrorerror守护层自身守护层内部异常被隔离时触发;生产环境静默,仅走 logger

duplicate.triggered

js
{
  level: 'warn',
  event: 'duplicate.triggered',
  message: '请勿重复提交(第2次)',
  namespace: 'requestGuard',
  timestamp: 1717315200000,
  data: {
    strategy: 'ignore',
    capability: 'duplicate',
    config: { /* 原始请求配置 */ },
    options: { /* 当前生效的 duplicate 配置 */ },
    requestKey: 'post_/api/submit_...',
    key: 'post_/api/submit_...',         // requestKey 的别名
    debugInfo: { /* 标识生成依据,用于排查误判 */ },
    firstStack: '...',                    // 首次请求调用栈(captureStack 开启时)
    duplicateStack: '...',               // 重复请求调用栈
    stack: '...',                         // duplicateStack 的别名
    repeatCount: 2,
    pendingCount: 3,                      // 当前所有能力的活跃状态总数
    method: 'POST',
    url: '/api/submit',
    message: '请勿重复提交(第2次)'
  }
}

retry.scheduled

js
{
  level: 'info',
  event: 'retry.scheduled',
  message: 'RequestGuard retry scheduled: /api/data',
  data: {
    capability: 'retry',
    config: { /* 原始请求配置 */ },
    options: { /* 当前生效的 retry 配置 */ },
    error,                                 // 本次失败捕获的错误
    attempt: 2,                            // 当前失败的是第几次尝试(1-based)
    retryIndex: 2,                         // 即将进入的第几次重试(1-based)
    nextAttempt: 3,                        // 下一次尝试序号(1-based)
    attempts: 3,                           // 配置的最大尝试次数
    delay: 600,                            // 本次重试等待时间(ms)
    status: 503,                           // 从错误中提取的 HTTP 状态码
    code: undefined                        // 从错误中提取的错误码
  }
}

retry.exhausted

表示 retry 生命周期停止,不只是"次数用尽"。停止原因通过 data.reason 区分:

js
{
  level: 'warn',
  event: 'retry.exhausted',
  message: 'RequestGuard retry exhausted: /api/data',
  data: {
    capability: 'retry',
    config: { /* 原始请求配置 */ },
    options: { /* 当前生效的 retry 配置 */ },
    error,                                 // 最后一次失败捕获的错误
    attempt: 3,                            // 停止时的尝试序号(1-based)
    retryIndex: 3,
    attempts: 3,                           // 配置的最大尝试次数
    reason: 'attempt-limit',               // 停止原因,见下表
    status: 503,
    code: undefined
  }
}
reason含义
attempt-limit达到最大尝试次数
non-retryable状态码 / 错误码不在可重试范围内,默认不可重试判断
circuit-open熔断器打开,重试被熔断拦截
hard-stopclearState() / uninstall() 等主动终止
policy-deniedcanRetry 显式返回 false 或非 true

retry 不触发 notify

retry 的所有事件只走 logger,不触发 notify。retry 停止后返回原始错误给业务,由业务的错误处理决定是否提示用户。

circuitBreaker.blocked

js
{
  level: 'warn',
  event: 'circuitBreaker.blocked',
  message: 'RequestGuard circuit breaker blocked: POST:/api/payment/create',
  data: {
    capability: 'circuitBreaker',
    circuitKey: 'POST:/api/payment/create',
    state: 'CIRCUIT_BREAKER',
    failCount: 5,
    openedAt: 1717315200000,
    config: { /* 原始请求配置 */ }
  }
}

circuitBreaker.stateChange

js
{
  level: 'warn',
  event: 'circuitBreaker.stateChange',
  message: 'RequestGuard circuit breaker state changed: POST:/api/payment/create NORMAL → CIRCUIT_BREAKER',
  data: {
    capability: 'circuitBreaker',
    circuitKey: 'POST:/api/payment/create',
    fromState: 'NORMAL',
    toState: 'CIRCUIT_BREAKER',
    failCount: 5,
    openedAt: 1717315200000
  }
}

circuitBreaker.halfOpenProbe

js
{
  level: 'info',
  event: 'circuitBreaker.halfOpenProbe',
  message: 'RequestGuard circuit breaker half-open probe: POST:/api/payment/create',
  data: {
    capability: 'circuitBreaker',
    circuitKey: 'POST:/api/payment/create',
    probePassCount: 0,                     // 当前已放行的试探请求数
    probeCount: 1                          // 配置的试探请求数上限
  }
}

circuitBreaker.recovered

js
{
  level: 'info',
  event: 'circuitBreaker.recovered',
  message: 'RequestGuard circuit breaker recovered: POST:/api/payment/create',
  data: {
    capability: 'circuitBreaker',
    circuitKey: 'POST:/api/payment/create',
    previousState: 'HALF_OPEN',
    newState: 'NORMAL'
  }
}

requestGuard.internalError

js
{
  level: 'error',
  event: 'requestGuard.internalError',
  message: 'RequestGuard internal error: <phase>',
  data: {
    phase: '...',          // 异常发生阶段,如 capability:install / pipeline / notify
    error: Error,          // 被隔离的内部异常
    capability: '...'      // 涉及的能力(可选)
  }
}

守护层自身异常被隔离后,请求会直接穿透到真实网络出口(见 系统特性 - 智能降级)。这个事件用于排查守护层自身的 bug,生产环境只走 logger、不裸打 console。

🔔 Notify 触发目录

notify 是统一的 UI 提示出口。guard 主动触发的用户提示都走这里,内部已隔离其异常(提示失败不影响请求结果)。真实网络错误、业务错误码不通用进入 notify——那些由业务的错误处理负责。

触发时机capability触发条件说明
duplicate 命中duplicateshowToast: true 且命中重复ignore 静默挂起 / block 拒绝 / reuse 等待均触发
熔断拦截circuitBreaker熔断打开,请求被拒绝请求未发出
熔断状态变更circuitBreaker状态在 NORMAL/CIRCUIT_BREAKER/HALF_OPEN 间切换让业务感知保护状态变化
retry默认不触发 notify,仅走 logger

duplicate 命中时的 payload

字段类型描述
messagestring提示文案(含重复次数,如"请勿重复提交(第2次)")
strategystring触发策略(ignore / block / reuse
capabilitystring'duplicate'
configobject原始请求配置
requestKeystring请求唯一标识
repeatCountnumber重复次数
pendingCountnumber当前所有能力的活跃状态总数
methodstring请求方法
urlstring请求地址

熔断拦截时的 payload

字段类型描述
messagestring提示文案(如"请求已被熔断拦截: POST:/api/payment")
capabilitystring'circuitBreaker'
circuitKeystring熔断单元标识
statestring当前熔断状态(CIRCUIT_BREAKER
failCountnumber失败次数
openedAtnumber熔断开始时间戳

熔断状态变更时的 payload

字段类型描述
messagestring提示文案(如"熔断状态变更: POST:/api/payment 熔断 → 半开")
capabilitystring'circuitBreaker'
circuitKeystring熔断单元标识
fromStatestring变更前状态
toStatestring变更后状态
failCountnumber失败次数
openedAtnumber熔断开始时间戳

🔧 接入示例

javascript
const requestManager = setupRequestGuard(axios, {
  notify: (payload) => {
    // 按能力分发到不同 UI 出口
    if (payload.capability === 'duplicate') {
      Toast.show(payload.message);
    } else if (payload.capability === 'circuitBreaker') {
      // 熔断拦截提示用户稍后重试,状态变更可静默或仅日志
      if (payload.state === 'CIRCUIT_BREAKER') {
        Toast.show({ content: payload.message, type: 'error' });
      }
    }
  },
  logger: new ConsoleRequestGuardLogger({ devOnly: true })
});

自定义 logger 接入见 消息与日志系统 - 自定义 Logger

基于 MIT 许可发布