Communication patterns
Choose synchronous calls for immediate answers and asynchronous messages for decoupled workflows, while designing every boundary for latency and failure.
Use synchronous calls when the caller needs the answer now
HTTP or RPC is appropriate for queries, validation that must complete before a response, and commands whose immediate result matters. Keep call chains short: every hop adds latency and another way for the request to fail.
Set explicit deadlines. A default client timeout is rarely a product decision. Propagate cancellation and include correlation identifiers so one request can be followed across services.
- Bounded timeout
- Authentication and authorisation
- Idempotency for retried commands
- Compatible request and response schema
- Useful errors without internal leakage
Use events to announce completed facts
An event says something already happened: OrderPlaced, PaymentCaptured, or ProfileUpdated. Consumers decide independently what to do. This reduces temporal coupling because the producer does not need every consumer online.
Events should carry stable identifiers, occurrence time, schema version, and enough context for consumers to act without repeatedly calling the producer. Do not put secrets into a broadly distributed event.
Assume messages can arrive more than once
Most practical brokers provide at-least-once delivery. A consumer may finish its work and crash before acknowledging the message, causing redelivery. Make handlers idempotent with a processed-message record, a naturally idempotent write, or a business key.
Ordering is normally local to a partition or entity key, not global. Design state transitions so stale events are rejected or safely ignored.
Publish reliably with an outbox
Treat contracts as products
Document semantics, not only field types. State whether absence differs from null, whether amounts are minor units, which errors are retryable, and what compatibility consumers can expect.
Use consumer-driven contract tests where they help, but keep ownership clear: a producer must not become unable to improve because consumers assert accidental implementation details.
Can you explain “Communication patterns” without reaching for the API reference?
Describe the main trade-off, one failure mode, and the decision you would make in a real project.