DEV Community

Cover image for Create a delivery once, even when your Node worker retries
SendRelay for SendRelay

Posted on

Create a delivery once, even when your Node worker retries

You run an online pharmacy in Wuse 2, Abuja. A customer confirms an order, and your checkout worker starts a delivery. The request times out just as the worker loses its connection. Did the task get created? Retrying with a fresh request can leave your team looking at two dispatches for one order.

Relay lets your backend attach an idempotency key to task creation. Keep that key tied to the order's delivery intent, and a retry can recover the existing task. The customer sees one delivery; your ops team has one task to track. Here is how to wire that into a Node worker.

What you'll build

A Node function that creates a package delivery for an Abuja order and safely retries an uncertain result with the same key. You'll use the Node SDK and the task creation guide.

import { RelayClient } from '@relay-sdk/sdk-node';

const apiKey = process.env.RELAY_API_KEY;
if (!apiKey) throw new Error('RELAY_API_KEY is required');
const relay = new RelayClient({ apiKey });

type Order = { id: string };

export async function createOrderDelivery(order: Order) {
  // Persist the order ID before dispatching this job. Reuse it on every retry.
  const idempotencyKey = `order:${order.id}:delivery:v1`;
  const result = await relay.tasks.create({
    taskType: 'PACKAGE_DELIVERY',
    externalId: order.id,
    stages: [
      {
        type: 'PICKUP',
        location: { latitude: 9.0765, longitude: 7.3986, address: 'Wuse 2, Abuja' },
        instructions: 'Ask for the pharmacy desk',
        items: [{
          name: 'Packed order',
          estimatedValue: 500000,
          estimatedWeight: 'LIGHT',
          estimatedSize: 'BOX',
        }],
      },
      {
        type: 'DROPOFF',
        location: { latitude: 9.0579, longitude: 7.4951, address: 'Garki, Abuja' },
        instructions: 'Call the recipient on arrival',
      },
    ],
  }, { idempotencyKey });

  // Store this ID against your order so later events can update the right row.
  return { taskId: result.task.id, duplicate: result.idempotency.duplicate === true };
}
Enter fullscreen mode Exit fullscreen mode

Install the package with npm install @relay-sdk/sdk-node. Keep RELAY_API_KEY on your server. The SDK sends the explicit key as an Idempotency-Key header. Its automatically generated POST keys help within a request, but a stable order-based key is what makes a later job retry refer to the same delivery.

Retry the same intent, not a new delivery

If the worker times out or its queue redelivers the job, call createOrderDelivery(order) again with the same persisted order ID and the same delivery details. Do not add a timestamp or random value to the key. Relay looks up a task by account and key; a replay returns the existing task with idempotency.duplicate: true. The key is for one delivery intent. If the customer requests a genuinely new delivery, use a new versioned key.

The API describes a 24-hour validity window for this retry flow. Keep your own order-to-task record as the longer-lived source of truth. A timeout does not prove creation failed: retry with the same key, then record the returned task ID. If the API keeps failing, let your queue retry later with that same key rather than issuing an unkeyed create.

Try it without dispatching a rider

Start with a sk_test_... key from your Relay dashboard. Test-key task creation runs a simulation: it does not assign a real rider or move real money. The server selects the internal TEST payment path, so do not send paymentMethod: 'TEST'. You can pass simulationOutcome: 'SUCCESS' in the create body while checking the flow. Create the same order twice and check that the second result reports duplicate: true and the same task ID.

For the response shape, lifecycle, and test outcomes, see Create Task and Simulation Outcomes. For your checkout, get your API keys and keep the key generation on your backend.

Top comments (0)