Skip to content
Ocean-Atlasv0.1.0Canonical Knowledge

Asynchronous Request-Response

A service needs an answer from one or more other services, but those services are reached through a message broker rather than called directly — for decoupling, independent deployability, or fan-out to responders whose network address the caller should not need to know.

How do you give a synchronous caller an answer when the actual work happens through asynchronous message exchange, potentially involving several independent responders and state accumulated along the way?

  • Coupling — a broker decouples the caller and responder’s network addresses and availability, but they still share a message contract and topic name.
  • Latency — must be bounded by an explicit timeout per request-response leg, not left open-ended.
  • Consistency — partial results from independent responders may need to be merged before answering the original caller.
  • Failure handling — one non-responding leg must not hang the whole request.
  • Reuse — the same topic can be consumed by multiple independent responder services without the caller depending on their APIs directly.

Declare a @broker with a typed request-response topic for each request/answer pair and give each topic an explicit timeout. A coordinating @service uses the broker, issues typed requests, and maps the responses before answering its own synchronous API. Responder services connect their local logic to the same broker topics.

When the answer also depends on values that update independently, add a plain event topic and an optional service-local @context to cache or accumulate those values. Context and event caching extend the core request-response pattern; they are not required for every use.

flowchart LR
Client --> AnswerApi --> AnswerService
AnswerService -- question.timedate --> AnswerBroker
AnswerBroker -- question.timedate --> TimeDateService
AnswerService -- question.day --> AnswerBroker
AnswerBroker -- question.day --> DayService
DayTipService -- dayTip event, every 10s --> AnswerBroker
AnswerBroker -- dayTip event --> AnswerService
AnswerService -- update --> AnswerContext[(AnswerContext)]
@broker
AnswerBroker
engine = nats
configType = AnswerBrokerConfig
dayTip : String as event
question.day : _-String as request-response with timeout:1s
question.timedate : TimeDateRequest-TimeDateResponse as request-response with timeout:1s
@context
AnswerContext
tip : String (default=enjoy your day!)
@service
AnswerService
use broker AnswerBroker as svcBroker
use context AnswerContext as svcCtx
use function Func<TimeDateRequest,TimeDateResponse> as GetTimeDate
connect svcBroker.dayTip -> HandleDayTip(ctx:svcCtx)
connect GetTimeDate -> svcBroker.question.timedate & timeout(3:s)

This is a minimal illustrative fragment, not a complete duplicated example — see Working Examples for the full, runnable model.

  • The caller and responders don’t need each other’s network address, only a shared broker and topic contract.
  • Per-topic timeouts bound the worst-case latency of each leg.
  • When needed, a service-local context lets slow-changing values (like a cached tip) be refreshed independently of any single request.
  • Debugging a request requires broker visibility, not just a call stack.
  • Message contracts (request and response types) must stay in sync across independently deployed services.
  • The composed path only works while the broker infrastructure is running — there is no direct fallback path.
  • If every composed call is reachable as a directly callable API and a bounded fan-out is enough, prefer Synchronous API Composition — it has fewer moving parts.
  • If a request only needs a periodic or cached value rather than a live answer, a broker event topic alone, without request-response, may be enough.
  • Asynchronous Answer Aggregation — a coordinating service that answers synchronously while resolving day, time, and date through broker request-response, with a cached tip in context.
  • Broker-Based Math Service — the same request-response broker mechanics applied to routing typed arithmetic operations to specialized services.