# Messaging Fundamentals (/learn/concepts)



Two services need to work together: an Orders service takes a customer's order, and a dozen other things have to happen because of it — charge a card, reserve stock, email a receipt, update a dashboard. How do those services *talk*? You can have the Orders service call each of the others directly, or you can put something in the middle that carries the messages for it. That "something in the middle" is what this whole track is about.

Think of it like a busy office. People could walk to each other's desks every time they need something — fast when the other person is there, useless when they're out. Or they could drop notes in a central mailroom that sorts and delivers them. The mailroom never forgets to deliver, doesn't care who's at their desk right now, and lets one announcement reach a hundred people at once. **Messaging** is software's mailroom.

## Synchronous vs asynchronous — the idea [#synchronous-vs-asynchronous--the-idea]

The first choice in any conversation between two services is *whether the sender waits*.

**Synchronous** communication is a phone call. You dial, the other person picks up, you talk, you get an answer, and only then do you hang up and move on. The caller is blocked the whole time — if the other side is slow or down, the caller is stuck. It is simple and immediate, and you get an answer right away.

**Asynchronous** communication is leaving a voicemail or sending a letter. You say your piece and move on with your day; the recipient picks it up when they can and acts on it later. The sender is not blocked, the recipient does not have to be available at the same moment, and the work happens in the background.

<Mermaid
  chart="graph LR
  A1[&#x22;Orders Service&#x22;]
  B1[&#x22;Payments Service&#x22;]
  A1 -- &#x22;call & wait for reply&#x22; --> B1
  B1 -. &#x22;reply&#x22; .-> A1

  A2[&#x22;Orders Service&#x22;]
  M2{{&#x22;message channel&#x22;}}
  B2[&#x22;Payments Service<br/>(busy or offline)&#x22;]
  A2 -- &#x22;send & move on&#x22; --> M2
  M2 -. &#x22;delivered when ready&#x22; .-> B2

  class B1 client
  class A1,A2 client
  class M2 broker
  class B2 external"
/>

*Top: a synchronous call — the caller waits for a reply. Bottom: an asynchronous message — the sender hands off and continues; delivery happens when the receiver is ready.*

Neither is "better." A phone call is right when you genuinely need the answer *now* to continue (checking whether a credit card is valid). A voicemail is right when you just need the other side to *eventually* know something (a receipt should be emailed). Most real systems use both.

## Tight vs loose coupling — the idea [#tight-vs-loose-coupling--the-idea]

When the Orders service calls the Payments service directly, it has to know Payments exists, where it lives, that it is up, and how to talk to it. If Payments moves, scales, slows down, or fails, Orders feels it immediately. That is **tight coupling**: the two are wired straight to each other, and a change or failure in one ripples into the other.

Now add a fifth, sixth, and seventh thing that must happen on every order — fulfillment, analytics, fraud checks, loyalty points. With direct calls, the Orders service grows a hard-wired dependency on each one, and every new consumer means editing and redeploying Orders.

Put a broker in the middle and the picture changes. Orders publishes "an order was placed" to a channel and stops caring who listens. Payments, fulfillment, and analytics each subscribe on their own terms. Orders does not know they exist; they do not know Orders exists. That is **loose coupling**: services depend on a shared *channel*, not on each other. New consumers slot in without touching the producer, and one service being down no longer takes the sender down with it.

<Mermaid
  chart="graph LR
  D1[&#x22;Orders&#x22;]
  D2[&#x22;Payments&#x22;]
  D3[&#x22;Fulfilment&#x22;]
  D4[&#x22;Analytics&#x22;]
  D1 --> D2
  D1 --> D3
  D1 --> D4

  L1[&#x22;Orders&#x22;]
  BR{{&#x22;order-placed channel&#x22;}}
  L2[&#x22;Payments&#x22;]
  L3[&#x22;Fulfilment&#x22;]
  L4[&#x22;Analytics&#x22;]
  L1 -- publish --> BR
  BR --> L2
  BR --> L3
  BR --> L4

  class D1,D2,D3,D4,L1,L2,L3,L4 client
  class BR broker"
/>

*Left: direct calls — the producer is wired to every consumer and must change when the set of consumers changes. Right: via a broker — the producer publishes to one channel; consumers come and go independently.*

<Callout type="warn">
  **Pitfall:** loose coupling is not free. Asynchronous, broker-mediated messaging adds a hop, makes end-to-end flows harder to trace, and means "done" no longer means "everyone who cares has finished." You trade immediate, all-or-nothing simplicity for independence and resilience. Reach for it when services must scale, fail, and evolve separately — not for a single call that needs an answer right now.
</Callout>

## What a message broker is [#what-a-message-broker-is]

A **message broker** is the piece of infrastructure in the middle. Its job is narrow and important: accept messages from producers, hold them in named **channels**, and deliver them to the right consumers — then get out of the way.

A broker does the work that every messaging system would otherwise reinvent:

* **Decouples** producers from consumers in space (they need not know each other's location), in time (they need not run at the same moment), and in number (one producer, many consumers — or the reverse).
* **Buffers** bursts so a fast producer does not overwhelm a slow consumer.
* **Routes** each message to the consumers that asked for it, by channel name and pattern.
* **Applies delivery rules** — try once, try until acknowledged, preserve order, allow replay — depending on the channel type.

<Mermaid
  chart="graph LR
  PUB1[&#x22;Orders Service&#x22;]
  PUB2[&#x22;Inventory Service&#x22;]
  ENG{{&#x22;KubeMQ<br/>channels&#x22;}}
  C1[&#x22;Payments&#x22;]
  C2[&#x22;Fulfilment&#x22;]
  C3[&#x22;Analytics&#x22;]

  PUB1 -- &#x22;gRPC :50000&#x22; --> ENG
  PUB2 -- &#x22;REST :9090&#x22; --> ENG
  ENG --> C1
  ENG --> C2
  ENG --> C3

  class ENG broker
  class PUB1,PUB2,C1,C2,C3 client"
/>

*A simple topology: producers send to channels through one broker, which delivers to the consumers that subscribed — over whatever transport each client speaks.*

## Why distinct messaging patterns exist [#why-distinct-messaging-patterns-exist]

If a broker just "delivers messages," why does this track have four different patterns? Because **one size does not fit all**. Different jobs need different delivery contracts, and trying to serve them all with one mechanism makes every job worse.

Consider what changes from job to job:

| Question                                                     | Notifications | Order processing | Audit log          | "Is the card valid?" |
| ------------------------------------------------------------ | ------------- | ---------------- | ------------------ | -------------------- |
| Does the sender need a reply?                                | No            | No               | No                 | **Yes, now**         |
| Must every message survive a crash?                          | No            | **Yes**          | **Yes**            | No                   |
| Should each message go to *one* worker or *all* subscribers? | All           | **One**          | Replayable by many | One responder        |
| Does order matter?                                           | No            | Often            | **Yes**            | N/A                  |
| Can old messages be replayed later?                          | No            | No               | **Yes**            | No                   |

No single delivery rule answers all of these well. A pattern that guarantees nothing is lost and lets you replay history is overkill (and slower) for a fleeting "user is typing" notification. A fire-and-forget broadcast is dangerous for a payment that must not be processed twice. So messaging gives you a small set of **patterns**, each a deliberate trade-off between speed, durability, ordering, and shape of delivery. Picking the right one is most of the skill — and the rest of this track teaches you how.

## In KubeMQ [#in-kubemq]

<Callout type="info">
  **In KubeMQ:** KubeMQ *is* the broker — a single engine that hosts every channel type. Your services connect once, then publish to and subscribe from named channels using one client SDK. The same connection speaks Events, Events Store, Queues, and RPC; the channel type you choose decides the delivery contract. The channels in the topology above are just KubeMQ channels of different types behind one address (`localhost:50000`).
</Callout>

Connecting and publishing a single message is the smallest possible "hello, broker." Here the Orders service sends one order event to a channel — it does not know or care who is listening.

<Tabs groupId="language" items="['Go','Python','Node.js','Java','C#','Kotlin','C++','Rust','Ruby','Elixir']">
  <Tab value="Go">
    ```go title="publish.go"
    package main

    import (
        "context"
        "log"

        "github.com/kubemq-io/kubemq-go/v2"
    )

    func main() {
        ctx := context.Background()
        client, err := kubemq.NewClient(ctx,
            kubemq.WithAddress("localhost", 50000),
        )
        if err != nil {
            log.Fatal(err)
        }
        defer client.Close()

        err = client.SendEvent(ctx, kubemq.NewEvent().
            SetChannel("order-placed").
            SetBody([]byte(`{"orderId":"ORD-1234","status":"placed"}`)),
        )
        if err != nil {
            log.Fatal(err)
        }
        log.Println("Message sent — Orders does not wait for any consumer")
    }
    ```
  </Tab>

  <Tab value="Python">
    ```python title="publish.py"
    from kubemq.pubsub import Client as PubSubClient
    from kubemq.pubsub import EventMessage

    client = PubSubClient(address="localhost:50000")
    client.send_event(
        EventMessage(
            channel="order-placed",
            body=b'{"orderId":"ORD-1234","status":"placed"}',
        )
    )
    print("Message sent — Orders does not wait for any consumer")
    client.close()
    ```
  </Tab>

  <Tab value="Node.js">
    ```javascript title="publish.js"
    const { KubeMQClient } = require("kubemq-js");

    const client = new KubeMQClient({ address: "localhost:50000" });

    await client.sendEvent({
      channel: "order-placed",
      body: Buffer.from(JSON.stringify({ orderId: "ORD-1234", status: "placed" })),
    });

    console.log("Message sent — Orders does not wait for any consumer");
    ```
  </Tab>

  <Tab value="Java">
    ```java title="Publish.java"
    PubSubClient client = PubSubClient.builder()
        .address("localhost:50000")
        .clientId("orders-service")
        .build();

    client.sendEventsMessage(EventMessage.builder()
        .channel("order-placed")
        .body("{\"orderId\":\"ORD-1234\",\"status\":\"placed\"}".getBytes())
        .build());

    System.out.println("Message sent — Orders does not wait for any consumer");
    client.close();
    ```
  </Tab>

  <Tab value="C#">
    ```csharp title="Publish.cs"
    await using var client = new KubeMQClient(new KubeMQClientOptions());
    await client.ConnectAsync();

    await client.SendEventAsync(new EventMessage
    {
        Channel = "order-placed",
        Body = Encoding.UTF8.GetBytes("{\"orderId\":\"ORD-1234\",\"status\":\"placed\"}")
    });

    Console.WriteLine("Message sent — Orders does not wait for any consumer");
    ```
  </Tab>

  <Tab value="Kotlin">
    ```kotlin title="Publish.kt"
    val client = PubSubClient("localhost:50000")

    client.sendEvent(EventMessage(
        channel = "order-placed",
        body = """{"orderId":"ORD-1234","status":"placed"}""".toByteArray()
    ))

    println("Message sent — Orders does not wait for any consumer")
    client.close()
    ```
  </Tab>

  <Tab value="C++">
    ```cpp title="publish.cpp"
    #include <kubemq/client.h>
    #include <iostream>

    auto client = kubemq::PubSubClient("localhost:50000");

    kubemq::EventMessage event;
    event.channel = "order-placed";
    event.body = R"({"orderId":"ORD-1234","status":"placed"})";

    client.sendEvent(event);
    std::cout << "Message sent — Orders does not wait for any consumer" << std::endl;
    ```
  </Tab>

  <Tab value="Rust">
    ```rust title="publish.rs"
    use kubemq::prelude::*;
    use kubemq::EventBuilder;

    #[tokio::main]
    async fn main() -> kubemq::Result<()> {
        let client = KubemqClient::builder()
            .host("localhost")
            .port(50000)
            .build()
            .await?;

        let event = EventBuilder::new()
            .channel("order-placed")
            .body(br#"{"orderId":"ORD-1234","status":"placed"}"#.to_vec())
            .build();

        client.send_event(event).await?;
        println!("Message sent — Orders does not wait for any consumer");

        client.close().await?;
        Ok(())
    }
    ```
  </Tab>

  <Tab value="Ruby">
    ```ruby title="publish.rb"
    require 'kubemq'

    client = KubeMQ::PubSubClient.new(address: "localhost:50000", client_id: "orders-service")

    msg = KubeMQ::PubSub::EventMessage.new(
      channel: "order-placed",
      body: '{"orderId":"ORD-1234","status":"placed"}'
    )
    client.send_event(msg)
    puts "Message sent — Orders does not wait for any consumer"

    client.close
    ```
  </Tab>

  <Tab value="Elixir">
    ```elixir title="publish.exs"
    {:ok, client} = KubeMQ.Client.start_link(address: "localhost:50000", client_id: "orders-service")

    event = KubeMQ.Event.new(channel: "order-placed", body: ~s({"orderId":"ORD-1234","status":"placed"}))

    case KubeMQ.Client.send_event(client, event) do
      :ok -> IO.puts("Message sent — Orders does not wait for any consumer")
      {:error, err} -> IO.puts("Send failed: #{err.message}")
    end

    KubeMQ.Client.close(client)
    ```
  </Tab>
</Tabs>

That same `client` connection can also persist events, queue work for a single worker, or make a request and wait for a reply — each is one of the four patterns below.

### How KubeMQ does this → [#how-kubemq-does-this-]

<Cards>
  <Card title="Events" href="/learn/events" description="Real-time pub/sub — fire-and-forget broadcast to every active subscriber, at-most-once." />

  <Card title="Events Store" href="/learn/events-store" description="Persistent pub/sub — events stored on disk so late subscribers can replay from any position." />

  <Card title="Queues" href="/learn/queues" description="Point-to-point work distribution — one message to one worker, at-least-once with acknowledgment." />

  <Card title="RPC" href="/learn/rpc" description="Request/reply — send a command or query and wait for a response through the broker." />
</Cards>

## Where to go next [#where-to-go-next]

You now have the vocabulary: synchronous vs asynchronous, tight vs loose coupling, what a broker does, and why patterns differ. Next, learn the small set of shapes every messaging system reduces to — then how delivery, ordering, scaling, and routing actually work.

<Cards>
  <Card title="Interaction Styles" href="/learn/concepts/interaction-styles" description="The three shapes: pub/sub, point-to-point, and request/reply." />

  <Card title="Delivery Guarantees" href="/learn/concepts/delivery-guarantees" description="at-most-once, at-least-once, exactly-once; ack/nack, idempotency, and dead-letter queues." />

  <Card title="Ordering & Replay" href="/learn/concepts/ordering-and-replay" description="FIFO and per-key order, sequence numbers and offsets, replay, and event sourcing." />

  <Card title="Scaling & Flow" href="/learn/concepts/scaling-and-flow" description="Competing consumers vs fan-out, consumer groups, backpressure, and visibility." />

  <Card title="Channels & Routing" href="/learn/concepts/channels-and-routing" description="Channels as named destinations, wildcards, and multicast routing." />
</Cards>

<Cards>
  <Card title="Events" href="/learn/events" description="Real-time pub/sub pattern." />

  <Card title="Events Store" href="/learn/events-store" description="Persistent, replayable pub/sub pattern." />

  <Card title="Queues" href="/learn/queues" description="Point-to-point work queue pattern." />

  <Card title="RPC" href="/learn/rpc" description="Request/reply command and query pattern." />
</Cards>
