Synchronous Calls, Asynchronous Messaging, and Webhooks

Choose between synchronous APIs, queued messages, and webhooks by matching delivery behavior to latency needs, failure handling, and ownership boundaries.

published: reading time: 8 min read author: GeekWorkBench
Quick Summary

Synchronous HTTP fits bounded requests that need an immediate answer; queues hand work off for later, and webhooks deliver events to other systems. The article explains what acknowledgements promise, how retries create duplicates, and where durable acceptance, an outbox, and idempotency fit. Use these patterns to set clear delivery contracts, monitor failures, and protect webhook receivers.

Synchronous Calls, Asynchronous Messaging, and Webhooks

Introduction

Backend integrations can wait for an immediate response, hand work to a queue, or notify another system with a webhook. Each pattern changes how latency, retries, delivery guarantees, and failure recovery work across the boundary.

This article compares synchronous calls, asynchronous messaging, and webhooks, including what an acknowledgement means and how to handle duplicate delivery. It also covers durable acceptance, observability, and security for producers and consumers.

When to use each approach

Pattern Use it when Trade-off
Synchronous HTTP The operation is short and the caller needs an immediate answer Latency and availability are coupled across services
Asynchronous messaging Work can finish later, traffic is bursty, or consumers need independent recovery More state, monitoring, and duplicate-safe handlers
Webhook A partner needs event notifications without polling Delivery is at least once in practice; receiver endpoint must be reachable

Do not use a queue merely to hide a slow API if the user experience still requires an immediate result. Do not expose a synchronous endpoint that waits on long-running work with arbitrary timeouts. For long operations, return 202 Accepted with a status URL and document what “accepted” guarantees.

Implementation sketch: acknowledge, then process

A minimal HTTP handler should validate, persist, and enqueue before acknowledging. The durable write and queue publication should be atomic or coordinated with an outbox; otherwise a crash between them can lose work. See the outbox pattern for that failure boundary.

async function submitExport(request: Request): Promise<Response> {
  const input = await request.json();
  const job = await jobs.createAndEnqueue(input); // durable operation
  return Response.json(
    { id: job.id, statusUrl: `/exports/${job.id}` },
    { status: 202 },
  );
}

For a webhook receiver, verify the signature over the raw request body before trusting event fields, persist a delivery identifier, and return success only after durable acceptance. Keep business processing off the request path if it may exceed the sender’s timeout.

Production failures and mitigations

A synchronous dependency slows down and consumes every caller’s connection pool. Set deadlines, cap concurrency, and fail with a clear retryable response. A queue consumer can fall behind after a traffic spike; alert on oldest-message age and scale consumers against safe downstream capacity. A webhook endpoint can return 500 after it has already committed the event, causing a duplicate delivery; use an idempotency key and acknowledge only after storing the delivery.

Failure scenario What the caller sees Mitigation
The database commit succeeds but queue publication fails The request appears accepted, but no worker sees the job Use a transactional outbox and alert on unpublished outbox records
A worker finishes a side effect, then crashes before acknowledging the message The broker redelivers work that already ran Make handlers idempotent and record completion by stable message ID
A poison message fails on every delivery Retries consume capacity and block useful work Cap retries, move the message to a dead-letter queue, and provide a replay process
A webhook receiver commits an event but its response times out The sender retries a delivery the receiver already stored Deduplicate by event ID and return success after durable acceptance

Observability checklist

  • Record request or event IDs across producer, queue, worker, and receiver logs.
  • Measure synchronous latency and error rates by dependency and operation.
  • Track queue depth, oldest-message age, retry count, and dead-letter volume.
  • Track webhook delivery attempts, response codes, and acknowledgement lag.
  • Avoid logging full payloads when they contain personal or secret data.

Security and Compliance Notes

Use TLS, authenticate callers, authorize each operation, and validate webhook signatures with constant-time comparison. Rotate signing secrets and include a timestamp to limit replay windows, while still handling legitimate retries. Define event schemas and versioning so a new optional field does not break older consumers. A common mistake is treating HTTP 200 as proof that downstream business work completed; define exactly whether it means received, persisted, or finished.

For compliance, send only the fields a consumer needs, and set retention and deletion rules for queued messages, dead-letter queues, and webhook delivery records. Restrict access to payloads and keep secrets or personal data out of operational logs; retain event IDs and delivery metadata when an audit trail is required.

Quick Recap Checklist

  • Use synchronous requests when the caller needs an immediate result and the work is bounded.
  • Return 202 Accepted only after work is durably queued, with a way to check its outcome.
  • Treat webhook and queue delivery as repeatable, and deduplicate with stable event identifiers.
  • Document retry behavior, acknowledgement meaning, and failure handling for both sides.

Interview Questions

1. When should an API return 202 Accepted?
Return it when the server has durably accepted a request for later work but cannot claim the work is complete. Include a status resource or another documented way to learn the result.
2. Are webhooks guaranteed to arrive exactly once?
No. Senders retry on timeouts and transient errors, and a receiver may commit work before its acknowledgement is lost. Treat delivery as at least once and deduplicate by a stable event ID.
3. What problem does a message queue solve?
A queue decouples when a producer submits work from when a consumer processes it. It can absorb bursts and allow retries, but it adds operational state and does not remove the need for idempotent consumers.
4. What failure does a transactional outbox prevent?
It prevents a service from committing a database change but losing the corresponding message because publishing failed afterward. The business update and outbox record are committed together, then a separate publisher sends the event.
5. When should a webhook receiver acknowledge a delivery?
Acknowledge after it has verified and durably recorded the delivery. If the response is lost afterward, the sender may retry, so the receiver should deduplicate by a stable event or delivery ID.
6. What is a poison message, and how should a consumer handle one?
It is a message that repeatedly fails processing. Use bounded retries, move it to a dead-letter queue, and provide a safe investigation and replay process so it does not block useful work forever.
7. Why is oldest-message age often more useful than queue depth alone?
Queue depth shows how much work is waiting, but the oldest-message age shows how long a consumer has been unable to keep up. A large age can reveal a user-visible delay even when the total backlog is moderate.
8. What does a webhook signature check establish?
When computed and verified according to the sender's protocol, it helps establish that the signed request body came from the expected sender and was not changed in transit. It does not replace replay controls, payload validation, or authorization for the resulting action.
9. Why should a message consumer make side effects idempotent?
A consumer can finish work and fail before acknowledging the message, causing redelivery. Idempotent handling or deduplication by stable message ID prevents a repeated delivery from repeating the business effect.

Further Reading

Conclusion

Choose the communication pattern from the caller’s actual need. Keep short request-response work synchronous, move long or bursty work behind durable messaging, and use webhooks when another system needs event notifications. State what each acknowledgement means, because that contract determines what both sides can safely do next.

Category

Related Posts

Partial Failure, Ordering, and Eventual Consistency

Understand partial API failures, message ordering, and eventual consistency, then design status models and recovery paths clients can reason about.

#api-design #distributed-systems #consistency

Event Envelopes and Metadata for Reliable EDA

Learn how event envelopes separate transport context from payload, apply CloudEvents attributes, propagate correlation IDs, and validate messages safely.

#event-driven-architecture #cloudevents #messaging

Event Security and Sensitive Data in EDA

Secure event-driven systems with least-privilege identities, encrypted transport and payloads, careful data minimization, and a deliberate retention plan.

#event-driven-architecture #security #data-privacy