KubeMQ
Client SDKsJavaHow-to guidesRPC

Command Timeout

Handle KubeMQ Command execution timeouts with the Java SDK when no handler responds within the configured window.

Overview

A command timeout is the deadline you attach to a single RPC call so a caller never blocks forever waiting on a handler that isn't there or isn't responding. Commands are synchronous by design — the sender is parked until a reply arrives — so without a bound, a missing subscriber or a crashed handler turns one request into an indefinite hang that ties up a thread and cascades into upstream timeouts.

The timeout is set per call with timeoutInSeconds on CommandMessage, and it's enforced by the broker itself, not by client-side polling: the broker tracks the deadline server-side and terminates the pending request the moment it expires, regardless of what the calling thread is doing. When the window elapses with no response, sendCommand throws an exception instead of returning a reply — your signal to retry or fall back.

Gotchas: the broker can also surface a timed-out request as a general operation error rather than a dedicated timeout exception, so production code should catch broadly (Exception), not just KubeMQTimeoutException; a slow-but-alive handler and a completely absent one produce the same timeout behavior, so you can't tell them apart from the exception alone; and setting the timeout too short under normal load turns transient latency into false failures.

Prerequisites

  • KubeMQ server running on localhost:50000
  • Java SDK installed (implementation 'io.kubemq.sdk:kubemq-sdk-Java:3.1.1' (Gradle) or Maven dependency from Getting Started)

Code

CommandTimeoutExample.java
package io.kubemq.example.commands;

import io.kubemq.sdk.cq.*;

public class CommandTimeoutExample {
    private static final String ADDRESS = "localhost:50000";
    private static final String CLIENT_ID = "java-commands-command-timeout-client";
    private static final String CHANNEL = "java-commands.command-timeout";

    public static void main(String[] args) throws InterruptedException {
        // Create a client connected to the KubeMQ server
        CQClient client = CQClient.builder().address(ADDRESS).clientId(CLIENT_ID).build();
        client.ping();
        // Create the commands channel
        client.createCommandsChannel(CHANNEL);

        // Subscribe to handle commands (handler intentionally delays 3s)
        CommandsSubscription sub = CommandsSubscription.builder()
                .channel(CHANNEL)
                .onReceiveCommandCallback(cmd -> {
                    try { Thread.sleep(3000); } catch (InterruptedException e) { Thread.currentThread().interrupt(); }
                    client.sendResponseMessage(CommandResponseMessage.builder()
                            .commandReceived(cmd).isExecuted(true).build());
                })
                .onErrorCallback(err -> {})
                .build();
        // Start the command handler subscription
        client.subscribeToCommands(sub);
        Thread.sleep(300);

        // Send command with short timeout (expect timeout)
        System.out.println("Sending command with 1s timeout (handler takes 3s)...");
        try {
            client.sendCommand(CommandMessage.builder()
                    .channel(CHANNEL).body("Slow command".getBytes()).timeoutInSeconds(1).build());
        } catch (Exception e) {
            System.out.println("Timeout (expected): " + e.getMessage());
        }

        // Wait for handler to finish processing the first command before sending the second
        Thread.sleep(4000);

        // Send command with sufficient timeout (expect success)
        System.out.println("\nSending command with 5s timeout (handler takes 3s)...");
        try {
            CommandResponseMessage resp = client.sendCommand(CommandMessage.builder()
                    .channel(CHANNEL).body("Normal command".getBytes()).timeoutInSeconds(5).build());
            System.out.println("Success: " + resp.isExecuted());
        } catch (Exception e) {
            System.err.println("Error: " + e.getMessage());
        }

        // Clean up resources
        sub.cancel();
        client.deleteCommandsChannel(CHANNEL);
        client.close();
    }
}

How It Works

  • timeoutInSeconds(1) in CommandMessage sets the deadline at the broker level; when no response arrives within 1 second the broker terminates the pending request and the client receives a timeout exception.
  • The handler sleeps 3 seconds intentionally, guaranteeing the first command exceeds its deadline; the second command uses a 5-second timeout, which is sufficient.
  • Thread.sleep(4000) between the two commands waits for the handler to finish processing the first (already-timed-out) command before sending the second to avoid queue depth interference.
  • Catch Exception (not just KubeMQTimeoutException) in production because the broker can also return other error conditions when a deadline is exceeded.

Was this page helpful?

On this page