This commit is contained in:
dengqichen 2025-11-19 15:28:57 +08:00
parent fafec7278d
commit 8ebb7779e0
2 changed files with 46 additions and 5 deletions

View File

@ -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);
});

View File

@ -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
}
);
}
/**