TypeScript如何用supertest每分钟轮询GET接口直到返回ready状态
你当前代码的核心问题
你写的轮询逻辑无法正常运行,存在几个硬伤:
- 自定义的
delay如果是异步方法,你没加await,实际不会等待1分钟,会以最高频发起请求,直接把服务压挂 - 状态取值路径写错了,对照你给出的返回示例,状态字段是嵌套在
body.state.state下,你直接取response.body.state拿到的是对象,永远不等于字符串ready,会直接触发死循环 - 没做大小写兼容,你自己提到接口可能返回大写开头的
Ready,直接全等匹配会判定失败 - 没有超时兜底,万一服务启动失败卡在
sending data或者validating阶段,代码会无限循环跑下去,永远无法终止 - 没有错误处理,某一次请求遇到网络波动、返回5xx,代码会直接抛错中断,不会继续重试
- 用
var声明变量,存在作用域污染问题,TS环境下不推荐使用
TypeScript 可直接落地的实现
首先定义类型安全的延迟工具方法:
const delay = (ms: number): Promise<void> => new Promise(resolve => setTimeout(resolve, ms));
轮询逻辑直接适配supertest + cucumber的使用场景:
When(/^service is up and running$/, async () => { // 可根据实际场景调整配置 const POLL_INTERVAL = 60000; // 轮询间隔1分钟 const MAX_WAIT_DURATION = 10 * 60 * 1000; // 最长等待10分钟,比预期的7分钟启动时长留足冗余 const startTimestamp = Date.now(); let lastKnownState = ''; let lastRequestError = ''; while (Date.now() - startTimestamp < MAX_WAIT_DURATION) { try { const response = await request .get('/api/status/') .set('Accept', 'application/json') .auth('user', 'password') .timeout(10000); // 单次请求10秒超时,避免某一次请求卡死后整个流程挂住 // 可选链判空+统一转小写,兼容接口结构异常和返回值大小写差异 const currentState = response.body?.state?.state?.toLowerCase?.() ?? ''; lastKnownState = currentState; if (currentState === 'ready') { console.log('Service is fully ready'); return; } console.log(`Service current state: ${currentState}, msg: ${response.body?.state?.msg ?? 'no msg'}, retry after 1 minute`); } catch (err) { lastRequestError = err instanceof Error ? err.message : String(err); console.log(`Fetch status failed: ${lastRequestError}, retry after 1 minute`); } // 必须加await,保证轮询间隔严格生效 await delay(POLL_INTERVAL); } // 超时直接抛错终止流程,避免死循环 throw new Error(`Service not ready after 10 minutes, last state: ${lastKnownState}, last error: ${lastRequestError}`); });
实现要点说明
- 所有异步调用都显式加了
await,轮询间隔严格按配置执行,不会出现无意义的高频请求 - 取值用可选链做了多层判空,就算接口临时返回异常结构,也不会报
Cannot read property of undefined的错误 - 状态值统一转小写比对,兼容
Ready/READY/ready各种大小写返回场景 - 加了最长等待时长兜底,超时直接抛错终止流程,不会出现无限循环
- 单次请求设置了独立超时,不会因为某一次请求卡死导致整个轮询挂住
- 异常场景做了捕获,网络波动、接口临时报错不会中断轮询,会按间隔继续重试
- 所有变量用
let/const声明,没有var的作用域问题,符合TS编码规范 - 加了必要的日志输出,排查问题的时候可以直接看到每一轮轮询的状态、报错信息,不需要额外加断点调试
内容的提问来源于stack exchange,提问作者Wicky
相关产品推荐
相关产品推荐

