KubeMQ
Client SDKsJavaHow-to guidesRPC

Cached Query

Cache KubeMQ Query responses with the Java SDK using a cache key and TTL to serve repeated requests faster.

Overview

Query response caching lets the broker answer repeat requests without re-running your handler — useful when a query is expensive to compute (a database lookup, an aggregation, a downstream call) but the same input is asked for repeatedly in a short window. Only the first request pays the processing cost; every other caller gets the same answer straight from the broker.

Set cacheKey(...) and cacheTtlInSeconds(...) on the QueryMessage. The first query with a given key is a miss: it reaches the handler, and the broker stores the response under that key for the TTL. A subsequent query with the same key is a hit — the broker returns the stored response directly, and the handler is not invoked again until the TTL expires.

Gotchas: the cache is keyed by the string you choose, not by the query body — if the underlying data changes mid-TTL, callers can get a stale answer until it expires. Keys are scoped per channel, so the same key on another channel is a separate entry. Setting cacheTtlInSeconds(0) or omitting cacheKey disables caching for that request even on a caching channel.

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

CachedQueryExample.java
package io.kubemq.example.queries;

import io.kubemq.sdk.cq.*;

public class CachedQueryExample {
    private static final String ADDRESS = "localhost:50000";
    private static final String CLIENT_ID = "java-queries-cached-query-client";
    private static final String CHANNEL = "java-queries.cached-query";

    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 queries channel
        client.createQueriesChannel(CHANNEL);

        // Subscribe to handle queries (responses may be cached)
        QueriesSubscription sub = QueriesSubscription.builder()
                .channel(CHANNEL)
                .onReceiveQueryCallback(query -> {
                    System.out.println("Handler invoked for: " + query.getId());
                    client.sendResponseMessage(QueryResponseMessage.builder()
                            .queryReceived(query).isExecuted(true)
                            .body("cached-result".getBytes()).build());
                })
                .onErrorCallback(err -> System.err.println("Error: " + err.getMessage()))
                .build();
        // Start the query handler subscription
        client.subscribeToQueries(sub);
        Thread.sleep(1000);

        // Build query with cache key and TTL
        QueryMessage q = QueryMessage.builder()
                .channel(CHANNEL).body("get-price".getBytes()).metadata("product=xyz")
                .timeoutInSeconds(10).cacheKey("price:xyz").cacheTtlInSeconds(60).build();

        // First request hits the handler; second may be served from cache
        QueryResponseMessage r1 = client.sendQuery(q);
        System.out.println("Response 1: " + new String(r1.getBody()));

        QueryResponseMessage r2 = client.sendQuery(q);
        System.out.println("Response 2: " + new String(r2.getBody()) + " (may be cached)");

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

How It Works

  • cacheKey("price:xyz") and cacheTtlInSeconds(60) instruct the broker to store the first response for this key and serve it directly for subsequent identical requests within 60 seconds, bypassing the handler entirely.
  • The first sendQuery() reaches the handler (you see "Handler invoked"); the second call returns the cached response — the handler is not invoked again until the TTL expires.
  • Cache keys are scoped to the channel; the same key on different channels is independent.
  • Set cacheTtlInSeconds(0) or omit cacheKey to disable caching for a specific request even on a channel that supports it.

Was this page helpful?

On this page