In this lesson, you will learn how to design Node.js workflows that pause execution for hours or days while waiting for external signals like human approval or API webhooks.
The Challenge of "Waiting"
In standard Node.js applications, holding an async function open with a setTimeout for several days is a recipe for disaster. If your server restarts, crashes, or deploys new code, all those "in-memory" wait states vanish instantly, leading to lost transactions and inconsistent system states.
To handle long-lived wait states, you must decouple the process execution from the process duration.
The Solution: State Externalization
Instead of keeping a function active in the event loop, you move the process into a "Wait State." When a task reaches a point where it must wait for an external trigger, it persists its current state to a database and terminates its execution.
Imagine an order fulfillment workflow:
- Initiate: Process the payment.
- Pause: Save the order status as
AWAITING_APPROVALin your database. - Terminate: Stop the Node.js process; free up memory.
- Resume: When the external event (like a webhook) arrives, a new worker fetches the saved state and resumes the workflow from the exact point it left off.
async function processOrder(orderId) {
const order = await db.orders.findById(orderId);
// Logic: Mark state and stop
await db.orders.update(orderId, { status: 'WAITING_FOR_ADMIN' });
// The function exits here. No memory is held.
return { paused: true };
}
// Later, triggered by an external API call:
async function handleApproval(orderId) {
const state = await db.orders.findById(orderId);
if (state.status === 'WAITING_FOR_ADMIN') {
// Resume workflow
await completeFulfillment(orderId);
}
}
By storing the state in a durable store (like Redis or PostgreSQL) rather than relying on the process memory, your system becomes resilient to infrastructure changes. When the external event eventually fires, your worker acts as an "orchestrator" that picks up the dormant data and pushes the workflow into its next state.
Key Takeaway: Never use setTimeout for tasks longer than a few minutes; instead, persist the task state to a database and terminate the process, resuming only when the external event signals your worker to continue.