# Command Group (/sdks/rust/how-to/rpc/command-group)



## Overview [#overview]

A command **consumer group** turns a single command handler into a scalable worker pool: run multiple identical instances subscribed with the same group name, and the broker load-balances each incoming command to exactly one member instead of broadcasting it to all of them. This is how you add capacity to handle a growing command volume — start more workers in the same group — without changing anything on the caller's side.

Every subscriber passes the same `group` alongside `channel` to `subscribe_to_commands`; the broker tracks membership and picks one live member per command. `send_command` on the caller side is unaware groups exist — it just awaits a response, which comes back from whichever handler happened to process it via `send_command_response`.

**Gotchas:** group membership is scoped per channel — subscribers on the same channel with *different* group names each get their own full copy of every command (fan-out), which looks like a bug when you expected load-balancing. A slow handler still holds up the caller's timeout, since only one worker is ever picked. And if every member of the group is offline when a command arrives, the send simply fails or times out — commands aren't queued or replayed for a group that has no active listener.

## Prerequisites [#prerequisites]

* KubeMQ server running on `localhost:50000`
* Rust SDK installed (`cargo add kubemq`)

## Code [#code]

```rust title="main.rs"
use kubemq::prelude::*;
use kubemq::{CommandBuilder, CommandReplyBuilder};
use std::time::Duration;

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

    let channel = "rust-rpc.command-group";
    let group = "cmd-handler-group";

    let rc1 = client.clone();
    let sub1 = client.subscribe_to_commands(channel, group,
        move |cmd| { let c = rc1.clone(); Box::pin(async move {
            println!("Handler-1: id={}", cmd.id);
            let reply = CommandReplyBuilder::new().request_id(&cmd.id).response_to(&cmd.response_to).build();
            let _ = c.send_command_response(reply).await;
        })}, None,
    ).await?;

    let rc2 = client.clone();
    let sub2 = client.subscribe_to_commands(channel, group,
        move |cmd| { let c = rc2.clone(); Box::pin(async move {
            println!("Handler-2: id={}", cmd.id);
            let reply = CommandReplyBuilder::new().request_id(&cmd.id).response_to(&cmd.response_to).build();
            let _ = c.send_command_response(reply).await;
        })}, None,
    ).await?;

    tokio::time::sleep(Duration::from_millis(500)).await;

    for i in 0..5 {
        let cmd = CommandBuilder::new()
            .channel(channel)
            .body(format!("cmd-{}", i).into_bytes())
            .timeout(Duration::from_secs(10))
            .build();
        let resp = client.send_command(cmd).await?;
        println!("Response {}: executed={}", i, resp.executed);
    }

    sub1.unsubscribe().await;
    sub2.unsubscribe().await;
    client.close().await?;
    Ok(())
}
```

## How It Works [#how-it-works]

* Both handlers join the same `group`, so each command is delivered to exactly one handler.
* The server distributes commands across group members for load balancing.
* Review timeouts, channel names, and client IDs before running against shared environments.
* Run the program while the server from the prerequisites is available.

## Related [#related]

* [RPC overview](/learn/rpc)
* [Rust SDK Reference](/sdks/rust/reference/rpc)
* [Command Send](/sdks/rust/tutorials/command-send)
