Skip to content
Back to site

Ordering

Ordering makes a receiver see an endpoint’s events in the order they were created. It is off by default, works per endpoint, and applies to outgoing deliveries only.

Set orderingEnabled on the subscription:

Terminal window
curl -X POST "$RAILHOOK_URL/api/v1/projects/$PROJECT_ID/subscriptions" \
-H "X-API-Key: $API_KEY" \
-H "Content-Type: application/json" \
-d '{"endpointId":"'"$ENDPOINT_ID"'","eventType":"order.*","orderingEnabled":true}'

With ordering off, deliveries to the same endpoint can overtake each other, which is where most of the throughput comes from.

Term Meaning
Sequence number A position stamped on each delivery to an endpoint, saying which of two deliveries came first regardless of when a worker picks them up. Sent as X-Sequence-Number; 0 when ordering is off.
Ordering buffer Where a delivery waits while the deliveries ahead of it have not finished. Waiting is a deferral: it does not use an attempt.
Gap The range between the last position the endpoint received and a waiting delivery, containing at least one unresolved delivery. The whole range is checked, not only the previous position.

A delivery goes out only when everything ahead of it for that endpoint has succeeded or been given up on. A delivery moved to Failed Messages stops blocking the ones behind it.

Without a limit, one delivery that never resolves would block the endpoint for good. So once a waiting delivery has waited out the gap timeout and nothing in the gap is still moving, it is let through out of order, and the event is counted.

Both conditions matter. A delivery between two retries is a gap about to close, so the deliveries behind it keep waiting however long they have waited. Otherwise the first ordinary retry would break the order, since the first retry delay and the gap timeout are both one minute. The timeout only releases a gap with nothing in flight and nothing due.

Setting Default
ORDERING_GAP_TIMEOUT_SECONDS 60
Metric webhook_ordering_gap_timeout_total
Cost Why
Throughput An ordered endpoint is effectively serial. Its response time is your ceiling.
Head-of-line blocking One slow or failing delivery holds up everything behind it until it resolves or the gap times out.
Replays go to the back A replay creates new deliveries with new sequence numbers, so a replayed event arrives after what is already waiting, not in its original place.
  • Order is per endpoint, never global. Two endpoints subscribed to the same event receive it independently.
  • Delivery is still at-least-once. Deduplicate on X-Delivery-Id or Idempotency-Key.
  • The order is best-effort under the gap timeout. If you need an order that never yields, put your own sequence field in the payload and check it in the receiver.
  • Incoming webhooks have no ordering: Railhook cannot know the order the provider intended. Use the provider’s own sequence field if it has one.