← Files Upstash RedisARCHIVED FILE

skills/upstash-workflow-js/features/wait-for-event.md

2.8 KB · Oct 2, 2026 · 00:21 UTC

↓ Download file

# Wait for Event

Use this feature to pause workflow execution until an external event arrives. It allows building asynchronous, event‑driven workflows without holding compute resources.

---

## How It Works

`context.waitForEvent()` suspends the workflow and registers a waiter under an event ID. When a matching `notify` call is sent, the workflow resumes with the provided event data.

• Each waiter has a timeout. If the event does not arrive in time, the workflow continues with `{ timeout: true }`.
• Maximum timeout depends on your pricing tier.
• Multiple workflow runs may wait on the same event ID; a notify call resumes all of them.

---

## Key Concepts & Pitfalls

### Event IDs

Use unique event IDs to avoid heavy fan‑out notifications.

Example patterns:
• `order-123-processing-complete`
• `user-42-email-verified`

### Race Conditions

A notify call sent _before_ the workflow begins waiting is lost.

To avoid this:
• Always inspect the notify response.
• Retry if no waiters were found.

---

## Combined Example

Below is a single TypeScript example showing waiting for an event, handling timeouts, and safely notifying:

```ts
import { serve } from "@upstash/workflow/nextjs";
import { Client } from "@upstash/workflow";

// Workflow that waits for an event
export const { POST } = serve(async (context) => {
  const { orderId } = context.requestPayload;
  const eventId = `order-${orderId}-processed`;

  // Wait for the event with timeout
  const { eventData, timeout } = await context.waitForEvent(
    "wait-for-order-processing", // step name
    eventId, // event id
    {
      timeout: "1d", // optional timeout
    }
  );

  if (timeout) {
    // handle timeout here
    await context.run("timeout-handler", async () => {
      console.log("Order processing timed out");
    });
    return;
  }

  // Continue workflow using eventData
  await context.run("process-completed-order", async () => {
    console.log("Order processed:", eventData);
  });
});

// External notifier (safe retry pattern)
const client = new Client({ token: "<WORKFLOW_TOKEN>" });

async function notifyProcessingComplete(orderId: string, payload: any) {
  const eventId = `order-${orderId}-processed`;

  // First attempt - returns array of NotifyResponse
  const waiters = await client.notify({ eventId, eventData: payload });

  if (waiters > 0) return waiters;

  // Retry if no workflows were waiting
  await new Promise((r) => setTimeout(r, 3000));
  return await client.notify({ eventId, eventData: payload });
}
```

---

## Best Practices

• Generate event IDs that uniquely identify a specific workflow instance.
• Always handle the timeout case explicitly.
• On notification, check the returned array length to detect if any workflows were waiting.
• Prefer one event ID per workflow run to avoid notifying large groups.

SHA-256: 7d3c875a4ee4b18ddb4a8241abd59ed79cefd344a5f283245664d2f1eb66344a