这是使用 try-catch、setTimeout 和递归编写非阻塞 while 循环的正确方法吗?
Is this the correct way to write a non-blocking while loop using try-catch, setTimeout and recursion?
我的服务器上有一个名为“/order”的端点。
当它被触发时,我需要将订单发送给 API。有时候因为ipfs上的一些数据下载时间太长,在try-catch块中命令失败,需要重新发送。
由于尝试重新发送订单直到成功的 while 循环会阻止其他请求,我想我可以自己使用递归和 setTimeout 来尝试发送相同的请求,比如 3 次每 5 分钟一次,如果第三次失败,则不再重试。
我想知道这是否是实现非阻塞功能的正确方法,是否有一些 vulnerabilities/things 我没有考虑到:
async function makeOrder(body, tries) {
if (tries > 0) {
let order;
try {
order = getOrderTemplate(body.shipping_address)
for (const index in body.line_items) {
order.items.push(await getItemTemplate(body.line_items[index]))
}
await sendOrderToAPI(order)
} catch (err) {
setTimeout(function(){
makeOrder(body, tries - 1)
}, 180000)
}
} else {
console.log("order n " + body.order_number + " failed")
//write failed order number to database to deal with it later on
}
}
一个重要的问题是,如果有问题,它会 return 一个 Promise,它不会在最终 API 调用完成时解决,而是在初始(失败)API 通话结束。这个:
setTimeout(function(){
makeOrder(body, tries - 1)
}, 180000)
未与外部的 async
函数正确链接。
因此,以下逻辑将失败:
makeOrder(body, 3)
.then(() => {
// All orders are made
})
改为 Promisify,以便递归调用可以轻松地与外部函数链接。
const delay = ms => new Promise(resolve => setTimeout(resolve, ms));
async function makeOrder(body, tries) {
if (tries > 0) {
let order;
try {
order = getOrderTemplate(body.shipping_address)
for (const index in body.line_items) {
order.items.push(await getItemTemplate(body.line_items[index]))
}
await sendOrderToAPI(order)
} catch (err) {
await delay(180_000);
return makeOrder(body, tries - 1);
}
} else {
console.log("order n " + body.order_number + " failed")
//write failed order number to database to deal with it later on
}
}
另一个可能的改进是,而不是 await
在循环中:
for (const index in body.line_items) {
order.items.push(await getItemTemplate(body.line_items[index]))
}
使用 Promise.all
,或允许一次获取多个模板的不同机制,而不必依次等待每个 one-by-one。
另一个潜在的问题是makeOrder
在超过允许的尝试次数时不会拒绝。也就是说,消费者将无法做到:
makeOrder(body, 3)
.catch((error) => {
// implement logic here to handle the error
})
如果您想允许上述操作,请在 makeOrder
的最后,在您记录的同时抛出:
} else {
console.log("order n " + body.order_number + " failed")
//write failed order number to database to deal with it later on
throw new Error('Failed');
}
我的服务器上有一个名为“/order”的端点。
当它被触发时,我需要将订单发送给 API。有时候因为ipfs上的一些数据下载时间太长,在try-catch块中命令失败,需要重新发送。
由于尝试重新发送订单直到成功的 while 循环会阻止其他请求,我想我可以自己使用递归和 setTimeout 来尝试发送相同的请求,比如 3 次每 5 分钟一次,如果第三次失败,则不再重试。
我想知道这是否是实现非阻塞功能的正确方法,是否有一些 vulnerabilities/things 我没有考虑到:
async function makeOrder(body, tries) {
if (tries > 0) {
let order;
try {
order = getOrderTemplate(body.shipping_address)
for (const index in body.line_items) {
order.items.push(await getItemTemplate(body.line_items[index]))
}
await sendOrderToAPI(order)
} catch (err) {
setTimeout(function(){
makeOrder(body, tries - 1)
}, 180000)
}
} else {
console.log("order n " + body.order_number + " failed")
//write failed order number to database to deal with it later on
}
}
一个重要的问题是,如果有问题,它会 return 一个 Promise,它不会在最终 API 调用完成时解决,而是在初始(失败)API 通话结束。这个:
setTimeout(function(){
makeOrder(body, tries - 1)
}, 180000)
未与外部的 async
函数正确链接。
因此,以下逻辑将失败:
makeOrder(body, 3)
.then(() => {
// All orders are made
})
改为 Promisify,以便递归调用可以轻松地与外部函数链接。
const delay = ms => new Promise(resolve => setTimeout(resolve, ms));
async function makeOrder(body, tries) {
if (tries > 0) {
let order;
try {
order = getOrderTemplate(body.shipping_address)
for (const index in body.line_items) {
order.items.push(await getItemTemplate(body.line_items[index]))
}
await sendOrderToAPI(order)
} catch (err) {
await delay(180_000);
return makeOrder(body, tries - 1);
}
} else {
console.log("order n " + body.order_number + " failed")
//write failed order number to database to deal with it later on
}
}
另一个可能的改进是,而不是 await
在循环中:
for (const index in body.line_items) {
order.items.push(await getItemTemplate(body.line_items[index]))
}
使用 Promise.all
,或允许一次获取多个模板的不同机制,而不必依次等待每个 one-by-one。
另一个潜在的问题是makeOrder
在超过允许的尝试次数时不会拒绝。也就是说,消费者将无法做到:
makeOrder(body, 3)
.catch((error) => {
// implement logic here to handle the error
})
如果您想允许上述操作,请在 makeOrder
的最后,在您记录的同时抛出:
} else {
console.log("order n " + body.order_number + " failed")
//write failed order number to database to deal with it later on
throw new Error('Failed');
}