# Cached Query (/sdks/csharp/how-to/rpc/query-cached)



## Overview [#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 `CacheTtlSeconds` 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 without invoking the handler. `CacheHit` on the response tells you which happened.

**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. Caching only helps when requests genuinely repeat with the same key.

## Prerequisites [#prerequisites]

* KubeMQ server running on `localhost:50000`
* C# SDK installed (`dotnet add package KubeMQ.SDK.CSharp`)

## Code [#code]

```csharp title="Program.cs"
// KubeMQ .NET SDK — Queries: Cached Response
//
// This example demonstrates query caching. The server caches the response
// and returns it directly for subsequent queries with the same cache key,
// without forwarding to the handler.
//
// Prerequisites:
//   - KubeMQ server running on localhost:50000
//   - Run Queries.HandleQuery in a separate terminal first
//   - dotnet run

using KubeMQ.Sdk.Client;
using KubeMQ.Sdk.Queries;
using KubeMQ.Sdk.Exceptions;
using System.Text;

await using var client = new KubeMQClient(new KubeMQClientOptions
{
    ClientId = "csharp-queries-cached-response-client",
});
await client.ConnectAsync();

Console.WriteLine("Connected to KubeMQ server");

try
{
    // First query — will be forwarded to the handler
    var response1 = await client.SendQueryAsync(new QueryMessage
    {
        Channel = "csharp-queries.cached-response",
        Body = Encoding.UTF8.GetBytes("get-user:42"),
        TimeoutInSeconds = 10,
        CacheKey = "user-42",
        CacheTtlSeconds = 60
    });

    Console.WriteLine($"First query - CacheHit: {response1.CacheHit}");
    Console.WriteLine($"Response: {Encoding.UTF8.GetString(response1.Body.Span)}");

    // Second query with same cache key — served from cache
    var response2 = await client.SendQueryAsync(new QueryMessage
    {
        Channel = "csharp-queries.cached-response",
        Body = Encoding.UTF8.GetBytes("get-user:42"),
        TimeoutInSeconds = 10,
        CacheKey = "user-42",
        CacheTtlSeconds = 60
    });

    Console.WriteLine($"\nSecond query - CacheHit: {response2.CacheHit}");
    Console.WriteLine($"Response: {Encoding.UTF8.GetString(response2.Body.Span)}");
}
catch (KubeMQTimeoutException)
{
    Console.WriteLine("Query timed out — no handler responded within 10 seconds");
}
catch (KubeMQOperationException ex)
{
    Console.WriteLine($"Operation error: {ex.Message}");
}
catch (Exception ex)
{
    Console.WriteLine($"Unexpected error: {ex.Message}");
}

Console.WriteLine("Done.");

```

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

* `CacheKey = "user-42"` and `CacheTtlSeconds = 60` on `QueryMessage` activate server-side response caching. The first query is forwarded to the handler; subsequent queries with the same `CacheKey` are served from the broker's cache without reaching the handler.
* `response1.CacheHit` is `false` on the first call (cache miss, handler invoked). `response2.CacheHit` is `true` on the second call (served from cache, no handler round-trip).
* `CacheTtlSeconds` controls how long the cached response is retained. After expiry, the next query with that key triggers a fresh handler invocation.
* Cache keys are scoped to the channel — the same key on different channels produces independent cache entries.

## Related [#related]

* [Pattern overview](/learn/rpc/getting-started)
* [C# SDK Reference](/sdks/csharp/reference)
* [Send Query](/sdks/csharp/tutorials/query-send)
* [Handle Query](/sdks/csharp/how-to/rpc/query-handle)
