My code takes care of various scenarios and is quite long, so I have reproduced with a boiled down pseudocode below:
const sendOrder = async function (Order) {
return new Promise(async (resolve) => {
console.log("order about to be place for " + Order.id + " at " + isoTime());
try {
const orderResponse = await sendOrderToBroker(Order);
console.log("order " + Order.id + "sent to broker at " + isoTime());
//Update db with details about successful order placement
models.orders
.update({
//Order status details
})
.then((countRowsUpdated) => {
console.log(
`Order ${orderId} success - ${countRowsUpdated} row(s) updated at time ${isoTime()}`
);
resolve(countRowsUpdated);
});
} catch (error) {
//Update db with details about failed order placement
models.orders
.update({
//failed order status details
})
.then((countRowsUpdated) => {
console.log(
`Order ${orderId} failure - ${countRowsUpdated} row(s) updated at time ${new Date().toISOString()}`
);
resolve(countRowsUpdated);
});
}
});
};
const run = async function () {
const ordersToBeProcessed = [];
const Order = {};
const orders = await models.orders.findAll(); //database request via sequelize
orders.map(async function (order) {
if (order.action === "entry") {
Order = populateOrderObject(order);
}
if (order.action === "exit") {
try {
currentPosition = await fetchCurrentPosition(); //network request via axios. Cause of the bug. Edited to include try... catch block
Order = populateOrderObject(order, currentPosition);
} catch (error) {
//Update db with details about failed fetch position
await models.orders
.update({
//failed fetch position details including error
})
}
}
ordersToBeProcessed.push(sendOrder(Order));
});
Promise.allSettled(ordersToBeProcessed).then((responses) => {
responses.map((response) => {
console.log(" response: " + response.status + ", value: " + response.value);
});
console.log("processedOrders.length is: " + processedOrders.length);
console.log("Number of responses is: " + responses.length);
if (orders.length === responses.length) {
setTimeout(run, 500);
}
});
};
setTimeout(run, 500);
This is the output below. For reference, orders 361 and 362 are entry orders with order.action === "entry", while orders 360 and 364 are exit orders:
Order engine started: 2020-10-12T21:22:47.712Z
running orders at time 2020-10-12T21:22:48.232Z
order about to be placed for 361 at time 2020-10-12T21:22:48.302Z
order about to be placed for 362 at time 2020-10-12T21:22:48.302Z
24
order about to be placed for 360 at time 2020-10-12T21:22:48.838Z
order about to be placed for 364 at time 2020-10-12T21:22:48.839Z
order 361 sent to broker at 2020-10-12T21:22:48.909Z
Order 361 success - 1 row(s) updated at time 2020-10-12T21:22:48.918Z
order 362 sent to broker at 2020-10-12T21:22:48.927Z
Order 362 success - 1 row(s) updated at time 2020-10-12T21:22:48.930Z
response: fulfilled, value: 1
response: fulfilled, value: 1
processedOrders.length is: 4
Number of responses is: 2
order 360 sent to broker at 2020-10-12T21:22:49.181Z
Order 360 success - 1 row(s) updated at time 2020-10-12T21:22:49.185Z
order 364 sent to broker at 2020-10-12T21:22:49.185Z
Order 364 success - 1 row(s) updated at time 2020-10-12T21:22:49.197Z
When order.action is equal to "exit", the Promise.allSettled (and also Promise.all) resolves without those exit orders. So, only the entry orders are included in the responses. The exit orders eventually resolve but the script terminates because the conditional setTimeout is never fired. What can I do to achieve the desired objective of having all processed orders resolve before Promise.allSettled.then runs? How do I handle the extra network request in the exit orders as I believe this is where the issue is coming from? I think this has to do with the event loop and handling of microtasks, but I can't move forward from there.