diff --git a/src/tools/automation-framework/actions/custom-action.js b/src/tools/automation-framework/actions/custom-action.js index 0002012..e5bfb11 100644 --- a/src/tools/automation-framework/actions/custom-action.js +++ b/src/tools/automation-framework/actions/custom-action.js @@ -1,4 +1,5 @@ const BaseAction = require('../core/base-action'); +const { ConfigurationError, TimeoutError } = require('../core/errors'); /** * 自定义动作 - 调用适配器中的自定义函数 @@ -11,20 +12,30 @@ class CustomAction extends BaseAction { const timeout = this.config.timeout || 300000; // 默认5分钟超时 if (!handler) { - throw new Error('缺少处理函数名称'); + throw new ConfigurationError('缺少处理函数名称', 'handler', { + action: 'custom', + config: this.config + }); } this.log('info', `执行自定义函数: ${handler}`); // 检查适配器中是否存在该函数 if (typeof this.context.adapter[handler] !== 'function') { - throw new Error(`自定义处理函数不存在: ${handler}`); + throw new ConfigurationError( + `自定义处理函数不存在: ${handler}`, + `adapter.${handler}`, + { availableHandlers: Object.keys(this.context.adapter) } + ); } // 使用 Promise.race 实现超时保护 const timeoutPromise = new Promise((_, reject) => { setTimeout(() => { - reject(new Error(`自定义函数执行超时 (${timeout}ms): ${handler}`)); + reject(new TimeoutError(`自定义函数: ${handler}`, timeout, { + handler, + params + })); }, timeout); }); diff --git a/src/tools/automation-framework/actions/retry-block-action.js b/src/tools/automation-framework/actions/retry-block-action.js index 2831350..7b6238d 100644 --- a/src/tools/automation-framework/actions/retry-block-action.js +++ b/src/tools/automation-framework/actions/retry-block-action.js @@ -1,13 +1,16 @@ const BaseAction = require('../core/base-action'); +const { ConfigurationError, TimeoutError, RetryExhaustedError } = require('../core/errors'); /** * 重试块动作 - 将一组步骤作为整体进行重试 + * 支持整体超时保护,防止无限重试 * * 配置示例: * - action: retryBlock * name: "支付流程" * maxRetries: 5 * retryDelay: 2000 + * totalTimeout: 300000 # 整体超时5分钟 * onRetryBefore: * - action: custom * handler: "regenerateCard" @@ -23,6 +26,7 @@ class RetryBlockAction extends BaseAction { steps = [], maxRetries = 3, retryDelay = 1000, + totalTimeout = 600000, // 默认10分钟整体超时 onRetryBefore = [], onRetryAfter = [] } = this.config; @@ -30,12 +34,30 @@ class RetryBlockAction extends BaseAction { const blockName = this.config.name || 'RetryBlock'; if (!steps || steps.length === 0) { - throw new Error('RetryBlock 必须包含至少一个步骤'); + throw new ConfigurationError( + 'RetryBlock 必须包含至少一个步骤', + 'steps', + { blockName, config: this.config } + ); } let lastError = null; + const startTime = Date.now(); for (let attempt = 0; attempt <= maxRetries; attempt++) { + // 检查整体超时 + const elapsed = Date.now() - startTime; + if (elapsed > totalTimeout) { + throw new TimeoutError( + `${blockName} (整体)`, + totalTimeout, + { + attempts: attempt, + elapsed, + lastError: lastError?.message + } + ); + } try { if (attempt > 0) { this.log('info', `${blockName} - 第 ${attempt + 1} 次重试...`); @@ -82,7 +104,15 @@ class RetryBlockAction extends BaseAction { } // 所有重试都失败 - throw new Error(`${blockName} 失败: ${lastError.message}`); + throw new RetryExhaustedError( + blockName, + maxRetries + 1, + { + lastError: lastError?.message, + stack: lastError?.stack, + totalTime: Date.now() - startTime + } + ); } /**