ToolJet 中 AI 请求超时自动重试的错误处理方案

文章导读
ToolJet 对接 AI 服务时,查询超时或 5xx 会让页面停在加载状态,用户往往不知道发生了什么。这个问题可以通过查询的 onFailure 事件手动处理:判断错误码,对可重试的请求用指数退避重新运行查询,同时把重试状态反映到按钮和日志里。以下方案不依赖 ToolJet 自带的重试功能,只用查询事件、JavaScript 和工具变量实现。
📋 目录
  1. 为 ToolJet 查询添加失败处理事件
  2. 根据错误码区分是否需要重试
  3. 实现指数退避重试循环
  4. 将重试状态绑定到 UI 按钮
  5. 在日志中记录最终失败原因
A A

ToolJet 对接 AI 服务时,查询超时或 5xx 会让页面停在加载状态,用户往往不知道发生了什么。这个问题可以通过查询的 onFailure 事件手动处理:判断错误码,对可重试的请求用指数退避重新运行查询,同时把重试状态反映到按钮和日志里。以下方案不依赖 ToolJet 自带的重试功能,只用查询事件、JavaScript 和工具变量实现。

处理方向:在查询 onFailure 事件中按错误码判断是否重试;可重试状态码为 408、429 和 5xx,400 等参数错误直接跳过。重试采用 1s、2s、4s 的指数退避,最多 3 次,并用工具变量记录次数。重试期间通过 loadingState 控制按钮禁用和文本。最终失败时把错误码、重试次数、耗时输出到浏览器 console。注意:查询成功时需要重置重试次数和开始时间,避免影响后续请求。

为 ToolJet 查询添加失败处理事件

在每个查询的设置里可以添加 onFailure 事件处理函数,而不仅是页面弹错。事件对象 event 包含 status 和 data 等属性,status 对应 HTTP 状态码,data 是服务端返回的响应体。先用 console.log 确认这两个字段的内容。

function handleFailure(event) {
  console.log('查询失败', event.status, event.data);
}

把这段代码填到查询的 onFailure 事件中,后续所有重试逻辑都从这里进入。如果事件对象中拿不到 status,说明网络层超时,也可以视为可重试条件。

根据错误码区分是否需要重试

AI 模型响应慢、限流和临时内部错误是常见可恢复问题;请求参数错误、鉴权失败这类 4xx 问题重试没有意义,反而浪费配额。判断逻辑应只放行 408、429 和 5xx 状态码。

ToolJet 中 AI 请求超时自动重试的错误处理方案
function isRetryable(status) {
  return status === 408 || status === 429 || status >= 500 || status === undefined;
}

在 onFailure 里先调用这个判断,再决定是否进入退避重试。

if (isRetryable(event.status)) {
  // 交给重试逻辑处理
} else {
  console.error('不可重试错误', event.status, event.data);
}

401、403、404 这类错误重试也无法解决,应直接进入错误提示,避免无意义调用。

实现指数退避重试循环

固定间隔重试容易在服务恢复前打爆接口,指数退避用 1 秒、2 秒、4 秒的间隔逐步拉长,给服务端留出时间。用工具变量记录当前尝试次数,跨事件保持状态。

const MAX_RETRIES = 3;
let attempt = variables.get('retryAttempt') || 0;

if (isRetryable(event.status) && attempt < MAX_RETRIES) {
  const delay = Math.pow(2, attempt) * 1000; // 1s, 2s, 4s
  variables.setValue('retryAttempt', attempt + 1);
  setTimeout(() => {
    queries['aiQuery'].run();
  }, delay);
} else {
  // 最终失败处理
}

这里 queries['aiQuery'] 要替换成实际查询标识,如果当前 ToolJet 版本使用 trigger 方法运行查询,就改为 queries['aiQuery'].trigger()。如果查询需要参数,把参数对象作为 run 的参数传入,例如 queries['aiQuery'].run({ prompt: input })。注意在查询的 onSuccess 中重置 retryAttempt,否则以后正常查询会带着旧计数。

ToolJet 中 AI 请求超时自动重试的错误处理方案
variables.setValue('retryAttempt', 0);

将重试状态绑定到 UI 按钮

页面在重试时不能只是空白,要把尝试次数和查询 loading 状态暴露到按钮上。ToolJet 中查询对象自带 loadingState,可以读取当前查询是否在运行。用工具变量绑定按钮禁用状态和文本。

// 按钮禁用状态
{{ queries['aiQuery'].loadingState > 0 || variables.get('retryAttempt') > 0 }}

// 按钮文本
{{ variables.get('retryAttempt') > 0 ? 'AI 请求重试中 (' + variables.get('retryAttempt') + '/3)' : '调用 AI' }}

当调用者看到按钮显示“重试中”并带序号,就知道系统正在处理,不是界面失去响应。查询最终失败后,按钮会恢复到可点击状态。

在日志中记录最终失败原因

重试三次仍失败时,需要保留排查信息。在 onFailure 的最终失败分支输出错误码、重试次数和请求总耗时。查询开始时记录 startTime,失败时用当前时间减掉该值即可得到耗时。

const startTime = variables.get('queryStartTime') || Date.now();
const elapsed = Date.now() - startTime;

console.error('AI 请求最终失败', {
  status: event.status,
  attempt: variables.get('retryAttempt'),
  elapsedMs: elapsed,
  data: event.data
});

查询开始前设置 variables.setValue('queryStartTime', Date.now())。打开浏览器开发者工具的 Console 面板,可以看到这条输入了状态码、次数和耗时的日志。最终失败后应把 retryAttempt 和 queryStartTime 清理干净,避免下一次请求误用旧数据。