poll.ts 1.3 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243
  1. /**
  2. * 通用轮询工具:等到断言函数返回 truthy,或超时。
  3. * 用于核心业务 E2E 中"提交生成 → 轮询进度"这种需要等待 LLM/TTS 的场景。
  4. */
  5. export interface PollOptions {
  6. /** 单次间隔 ms,默认 3000 */
  7. intervalMs?: number;
  8. /** 总超时 ms,默认 300000 (5 分钟)
  9. * 生产环境 1000 字 LangGraph 全链路实测 3 分 48 秒,留 1 分余量。
  10. * 之前 180s 在生产会刚好超时 48 秒导致 CORE-3 误报失败。
  11. */
  12. timeoutMs?: number;
  13. /** 自定义日志前缀 */
  14. label?: string;
  15. }
  16. export async function pollUntil<T>(
  17. fn: () => Promise<T | null | undefined | false>,
  18. opts: PollOptions = {}
  19. ): Promise<T> {
  20. const intervalMs = opts.intervalMs ?? 3000;
  21. const timeoutMs = opts.timeoutMs ?? 300_000;
  22. const label = opts.label ?? 'poll';
  23. const started = Date.now();
  24. // eslint-disable-next-line no-constant-condition
  25. while (true) {
  26. const result = await fn();
  27. if (result) return result;
  28. if (Date.now() - started >= timeoutMs) {
  29. throw new Error(
  30. `[${label}] 轮询超时 (${Math.round(timeoutMs / 1000)}s),最后一次结果为 ${JSON.stringify(result)}`
  31. );
  32. }
  33. await sleep(intervalMs);
  34. }
  35. }
  36. export function sleep(ms: number): Promise<void> {
  37. return new Promise((r) => setTimeout(r, ms));
  38. }