这是使用 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');
}