【发布时间】:2022-01-18 07:46:06
【问题描述】:
我将相同的查询发送到大量(好吧,n=5)相同的端点(几个 kubernetes 集群)并将结果整理在一起。我希望请求并行发出并在一段时间后超时;我希望将失败报告给用户,而不会妨碍进一步的进展。
作为所需输出的示例:
$ node find_broken_pods.js
tomato: error: timed out
Cluster Pod Reason
potato bar-foos Invalid PVC
potato foo-eggnog Invalid image
yoghurt spam-baz Invalid name
$ node find_broken_pods.js
Cluster Pod Reason
potato bar-foos Invalid PVC
potato foo-eggnog Invalid image
yoghurt spam-baz Invalid name
tomato what-bat Insufficient jQuery
第一次,无论出于何种原因,我们都未能从番茄集群中获得答案,但我们能够枚举其他集群的资源。第二次,没有超时,我们能够列出所有内容。
我之前想出这个:
export async function queryAll(): Promise<{cluster: string; deployments: V1Pod[]}[]> {
const out: {cluster: string; result: V1Pod[]}[] = [];
const promises: Promise<number>[] = [];
for (const cluster of Object.values(CLUSTERS)) {
promises.push(
Promise.race([
new Promise<number>((_, reject) => setTimeout(() => reject(new Error(`${cluster}: timed out`)), 5000)),
new Promise<number>((resolve, _) =>
getAllPods(cluster)
.then(pods => resolve(out.push({cluster: cluster, result: pods})))
),
])
);
}
await Promise.all(promises);
return out;
}
这确实并行运行所有内容,但单个故障会导致整个函数崩溃和烧毁。我想我可以把它改成这样:
export async function queryAll(): Promise<{cluster: string; deployments?: V1Deployment[]; error?: string}[]> {
const out: {cluster: string; result?: V1Pod[]; error?: string}[] = [];
const promises: Promise<number>[] = [];
for (const cluster of Object.values(CLUSTERS)) {
promises.push(
Promise.race([
new Promise<number>((resolve, _) =>
setTimeout(() => {
resolve(out.push({cluster: cluster, error: 'timed out'}));
}, 5000)
),
new Promise<number>((resolve, _) =>
getAllPods(cluster)
.then(pods => resolve(out.push({cluster: cluster, result: pods})))
),
])
);
}
await Promise.all(promises);
return out;
}
但是,我现在目睹了 Promise 的 两个 分支运行到完成,即 out 数组包含(一些)集群报告数据和 all或 none 我的集群报告超时:
- 如果没有超时,
Promise.all不会等待setTimeouts,但节点进程会(即如果我将超时设置为 60 秒,那么节点进程将仅在 60 秒后退出) - 如果达到任何超时,
Promise.all将等待超时发生...这意味着 所有setTimeouts 最终触发。
我反而希望Promise.race 失去的手臂会以某种方式被杀死或阻止运行。
有些事情告诉我,我的方法从根本上被打破了......我怎样才能提高我的容错能力?
【问题讨论】:
-
也许我所要做的就是使
out.push({cluster: cluster, error: 'timed out'})条件为out尚未包含来自cluster的数据? -
也许AbortController 可以帮助您摆脱困境?我不确定
getAllPods在幕后做什么,但如果它在做网络请求之类的事情,请检查您的网络请求库是否支持AbortSignal,并在setTimeout中调用abortController.abort()- 这可能会停止你的另一个Promise.race等待等待
标签: javascript typescript promise cancellation