You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用RTK Query轮询API直至获取'CLOSED'工作流状态?

如何用RTK Query实现工作流状态的轮询直到状态为'CLOSED'

方案1:利用RTK Query内置的refetchInterval实现条件轮询

RTK Query的useQuery钩子原生支持refetchInterval参数,可动态控制是否开启自动轮询,完全符合React钩子规则,无需手动编写定时器和useEffect:

const LoaderBox = (props: LoaderBoxProps) => {
  const { buildingId, devicesId } = props;

  const {
    data: runWorkflowData,
    error: runWorkflowError,
    isSuccess: isRunWorkflowSuccess,
  } = useRunWorfklowQuery({ buildingId, devicesId });

  const {
    data: runStatusData,
    error: runStatusError,
    isLoading: runStatusLoading,
  } = useGetWorkflowStatusQuery(
    isRunWorkflowSuccess ? { buildingId, runId: runWorkflowData.runId } : skipToken,
    {
      // 仅当状态未变为CLOSED时,每5秒重新请求一次
      refetchInterval: (data) => data?.runStatus !== 'CLOSED' ? 5000 : false,
      // 可选:切换到后台标签页时仍保持轮询
      refetchIntervalInBackground: true,
    }
  );

  // 直接通过接口返回值判断状态,无需额外维护useState
  const isRunFinished = runStatusData?.runStatus === 'CLOSED';

  return (
    <>
      {!runWorkflowError ? (
        <>
          <Text>Requested workflow run</Text>
          {isRunFinished ? <Text>Workflow finished</Text> : <Text>Workflow in progress</Text>}
        </>
      ) : null}
    </>
  );
};

方案2:正确使用lazyQuery手动控制轮询

如果需要更精细的自定义逻辑,可使用lazyQuery,注意正确解构返回值:lazyQuery返回的数组第一个元素是触发请求的函数,第二个是查询状态:

const LoaderBox = (props: LoaderBoxProps) => {
  const { buildingId, devicesId } = props;

  const {
    data: runWorkflowData,
    error: runWorkflowError,
    isSuccess: isRunWorkflowSuccess,
  } = useRunWorfklowQuery({ buildingId, devicesId });

  // 解构lazyQuery:第一个是触发函数,第二个是状态对象
  const [triggerGetStatus, { data: runStatusData }] = api.useLazyGetWorkflowStatusQuery();
  
  const [isRunFinished, setIsRunFinished] = useState(false);

  useEffect(() => {
    let intervalId: NodeJS.Timeout;

    // 工作流启动成功且未结束时,开始轮询
    if (isRunWorkflowSuccess && runWorkflowData?.runId && !isRunFinished) {
      const fetchStatus = async () => {
        const result = await triggerGetStatus({ buildingId, runId: runWorkflowData.runId });
        if (result.data?.runStatus === 'CLOSED') {
          setIsRunFinished(true);
          clearInterval(intervalId);
        }
      };

      // 发起首次请求
      fetchStatus();
      // 设置循环定时器
      intervalId = setInterval(fetchStatus, 5000);
    }

    // 组件卸载或依赖变更时清理定时器
    return () => clearInterval(intervalId);
  }, [isRunWorkflowSuccess, runWorkflowData, triggerGetStatus, isRunFinished, buildingId]);

  return (
    <>
      {!runWorkflowError ? (
        <>
          <Text>Requested workflow run</Text>
          {isRunFinished ? <Text>Workflow finished</Text> : <Text>Workflow in progress</Text>}
        </>
      ) : null}
    </>
  );
};

关于自定义baseQuery的重试问题

你的自定义getBaseQuery并非基于RTK Query内置的fetchBaseQuery,因此不支持原生retry参数。若需要重试逻辑,可手动在getBaseQuery中实现:

const getBaseQuery = async (apiPromise: Promise<ServiceModel>, retryCount = 3) => {
  let attempt = 0;
  while (attempt < retryCount) {
    try {
      const response = await apiPromise;
      if (response) {
        return { data: response };
      }
      throw new Error('No data received from service');
    } catch (err) {
      attempt++;
      if (attempt === retryCount) {
        return { error: err };
      }
      // 重试前等待1秒
      await new Promise(resolve => setTimeout(resolve, 1000));
    }
  }
  return { error: new Error('Max retries exceeded') };
};

不过对于轮询场景,方案1的refetchInterval已足够满足需求,无需额外添加重试逻辑。

内容的提问来源于stack exchange,提问作者Manthan Jamdagni

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.25 17:08:20