KubeMQ
Client SDKsElixirHow-to guidesRPC

Handle Command

Subscribe to handle incoming KubeMQ commands with automatic responses using the Elixir SDK.

Overview

A command handler is the receiving side of KubeMQ's Commands pattern — the code that actually does the work a caller is blocked waiting on. Instead of building your own request-routing layer on top of a queue, you register a handler once via the on_command callback passed to subscribe_to_commands, and KubeMQ delivers every matching command on that channel to it as a long-lived subscription, turning the channel into a synchronous RPC endpoint.

Handling happens inside on_command: you read the command's id, body, and reply_channel, run your business logic, then return a KubeMQ.CommandReply.new(request_id: cmd.id, response_to: cmd.reply_channel, executed: true, metadata: ...) — the SDK sends this reply automatically once the callback returns. Setting request_id and response_to to match the received command is what lets the broker correlate the reply back to the exact caller blocked on send_command; nothing else identifies which request the response belongs to.

Gotchas: the callback must return promptly and produce a valid CommandReply or the caller sees a timeout, since there's no separate explicit "send" call to retry; on_error only fires for transport-level subscription errors, not for exceptions raised inside on_command, so wrap risky logic yourself; and slow business logic inside the callback head-of-line blocks the next command on the same subscription.

Prerequisites

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

Code

main.exs
channel = "elixir-rpc.command-handle"
{:ok, client} = KubeMQ.Client.start_link(address: "localhost:50000", client_id: "elixir-cmd-handler")

{:ok, sub} =
  KubeMQ.Client.subscribe_to_commands(client, channel,
    on_command: fn cmd ->
      IO.puts("Processing command: #{cmd.body}")

      result = String.upcase(cmd.body)
      IO.puts("Result: #{result}")

      KubeMQ.CommandReply.new(
        request_id: cmd.id,
        response_to: cmd.reply_channel,
        executed: true,
        metadata: result
      )
    end,
    on_error: fn err ->
      IO.puts("Subscription error: #{err.message}")
    end
  )

IO.puts("Command handler ready on '#{channel}'")
Process.sleep(500)

cmd = KubeMQ.Command.new(channel: channel, body: "hello world", timeout: 10_000)

case KubeMQ.Client.send_command(client, cmd) do
  {:ok, resp} -> IO.puts("Response: executed=#{resp.executed}")
  {:error, err} -> IO.puts("Error: #{err.message}")
end

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

How It Works

  • The on_command callback processes the command and returns a %CommandReply{}
  • The reply's request_id and response_to must match the received command
  • on_error is called if the subscription encounters transport errors

Was this page helpful?

On this page