KubeMQ
Client SDKsElixirHow-to guides

Request-Reply

Implement synchronous request-reply messaging with the KubeMQ Elixir SDK using commands and queries.

Overview

Request-reply gives you synchronous RPC on top of KubeMQ's messaging fabric: a caller sends a query and blocks until the handler actually processing the request sends back a real answer — not just an acknowledgment. Reach for it whenever the caller needs a return value to proceed — a lookup, a computed result, a status check — the same shape as an HTTP call, but routed by KubeMQ instead of a service mesh or DNS.

A handler passed as on_query: to subscribe_to_queries builds a KubeMQ.QueryReply with request_id: query.id and response_to: query.reply_channel, returning it from the callback — copying those fields is what lets KubeMQ route the response to the one caller waiting, not broadcast it. The caller's send_query blocks until that reply arrives or its timeout elapses, returning {:ok, resp} with a body.

Gotchas: if no subscriber is listening — or the handler crashes before replying — send_query simply times out with {:error, err}; there's no way to distinguish "no handler" from "handler is slow" from the error alone. request_id and response_to must echo back the incoming query's values unchanged, or the reply is silently dropped or misrouted. If you don't actually need a return value, use commands instead — they only need an ack, so they don't tie up a caller waiting on a round trip.

Prerequisites

  • KubeMQ server running on localhost:50000
  • Elixir SDK installed ({:kubemq, "~> 1.0"} in mix.exs)

Code

main.exs
channel = "elixir-patterns.request-reply"
{:ok, client} = KubeMQ.Client.start_link(address: "localhost:50000", client_id: "elixir-req-reply")

{:ok, sub} =
  KubeMQ.Client.subscribe_to_queries(client, channel,
    on_query: fn query ->
      IO.puts("[Service] Processing request: #{query.body}")

      response_data =
        case query.body do
          "user:" <> id ->
            ~s({"id": "#{id}", "name": "Alice", "status": "active"})
          _ ->
            ~s({"error": "unknown request"})
        end

      KubeMQ.QueryReply.new(
        request_id: query.id,
        response_to: query.reply_channel,
        executed: true,
        body: response_data,
        metadata: "application/json"
      )
    end
  )

IO.puts("Service ready")
Process.sleep(500)

for user_id <- ["u-001", "u-002", "u-003"] do
  query = KubeMQ.Query.new(
    channel: channel,
    body: "user:#{user_id}",
    timeout: 10_000
  )

  case KubeMQ.Client.send_query(client, query) do
    {:ok, resp} ->
      IO.puts("Request user:#{user_id}#{resp.body}")

    {:error, err} ->
      IO.puts("Request failed: #{err.message}")
  end
end

KubeMQ.Subscription.cancel(sub)
KubeMQ.Client.close(client)

How It Works

  • The service subscribes to queries and returns user data based on the request body
  • Pattern matching on query.body routes requests to the correct handler logic
  • Multiple requests are sent sequentially, each receiving a JSON response

Was this page helpful?

On this page