Interface RouterContext


public interface RouterContext
Context passed to Router.onRequest(org.apache.kafka.common.protocol.ApiKeys, short, org.apache.kafka.common.message.RequestHeaderData, org.apache.kafka.common.protocol.ApiMessage, io.kroxylicious.proxy.router.RouterContext) for issuing requests to named routes and constructing the routing outcome.

A fresh instance is created for each Router.onRequest(org.apache.kafka.common.protocol.ApiKeys, short, org.apache.kafka.common.message.RequestHeaderData, org.apache.kafka.common.protocol.ApiMessage, io.kroxylicious.proxy.router.RouterContext) invocation. All methods on this interface, and all CompletionStage callbacks chained on futures returned by sendRequest(io.kroxylicious.proxy.topology.VirtualNode, org.apache.kafka.common.message.RequestHeaderData, org.apache.kafka.common.protocol.ApiMessage), execute on the same Netty event loop thread. Router implementations do not need to synchronise access to their own state.

Response delivery

The runtime automatically rewrites correlation IDs in responses to match the client's original request. Router implementations do not need to manage correlation IDs.

Error handling

If the CompletionStage<RouterResponse> returned by Router.onRequest(org.apache.kafka.common.protocol.ApiKeys, short, org.apache.kafka.common.message.RequestHeaderData, org.apache.kafka.common.protocol.ApiMessage, io.kroxylicious.proxy.router.RouterContext) completes exceptionally, or an unchecked exception escapes from onRequest, the runtime closes the client connection. For protocol-level errors (e.g. topic not found, authorization failure) routers should use respondWithError(org.apache.kafka.common.message.RequestHeaderData, org.apache.kafka.common.protocol.ApiMessage, org.apache.kafka.common.errors.ApiException) rather than throwing.

  • Method Details

    • virtualNode

      Optional<VirtualNode> virtualNode()
      Returns the virtual node of the broker that the client connected to.

      When the client connected to a broker-specific endpoint (i.e. an address that corresponds to a particular broker in the cluster topology), this returns that broker's virtual node. The router can use this to send requests — such as API_VERSIONS — to the specific broker the client believes it is talking to, rather than an arbitrary broker.

      When the client connected to a bootstrap address, this returns empty, because the proxy does not know which broker the client intended. In that case the router should use anyNode(String) to obtain a node for sending requests.

      Returns:
      the virtual node if the client connected to a broker-specific endpoint, or empty if the client connected to a bootstrap address
    • anyNode

      VirtualNode anyNode(String route)
      Returns a virtual node that, when passed to sendRequest(io.kroxylicious.proxy.topology.VirtualNode, org.apache.kafka.common.message.RequestHeaderData, org.apache.kafka.common.protocol.ApiMessage), causes the runtime to send the request to an arbitrary broker on the named route's cluster.

      This is used for initial discovery requests (e.g. METADATA, FIND_COORDINATOR) before the router has learned the cluster topology, and for requests that are not broker-specific. The runtime selects which broker to use. Repeated calls with the same route may return different nodes.

      Parameters:
      route - the name of the route
      Returns:
      a virtual node representing any broker on the route's cluster
      Throws:
      IllegalArgumentException - if the route name is not known
    • nodeForId

      VirtualNode nodeForId(int virtualNodeId)
      Converts an integer node ID from a protocol response body into a VirtualNode.

      This is the bridge between the Kafka wire protocol (which uses integer node IDs) and the VirtualNode API. Routers need this when interpreting node IDs in protocol messages — for example, broker node IDs in METADATA responses, coordinator node IDs in FIND_COORDINATOR responses, or leader IDs in partition metadata.

      Parameters:
      virtualNodeId - the integer node ID from a protocol response
      Returns:
      the corresponding virtual node
    • sendRequest

      CompletionStage<org.apache.kafka.common.protocol.ApiMessage> sendRequest(VirtualNode node, org.apache.kafka.common.message.RequestHeaderData header, org.apache.kafka.common.protocol.ApiMessage request)
      Sends a request to a specific broker identified by virtual node.

      The runtime derives the route from the virtual node and resolves it to a specific upstream broker address, opening a new connection if necessary. The returned stage completes when the broker produces a response.

      The node can be:

      Parameters:
      node - the virtual node of the target broker
      header - the request header
      request - the request body
      Returns:
      a stage that completes with the response body from the broker
      Throws:
      IllegalStateException - if the upstream address for the node is not yet known (metadata not yet reconciled)
    • sessionId

      String sessionId()
      Returns the unique identifier for the current proxy session.

      The same session ID is observed for all routers (including nested routers) and filters that handle requests from a given client connection.

      Returns:
      the unique identifier for the current proxy session
    • authenticatedSubject

      Subject authenticatedSubject()

      Returns the client subject.

      Depending on configuration, the subject can be based on network-level or Kafka protocol-level information (or both):

      • This will return an anonymous Subject (one with an empty principals set) when no authentication is configured, or the transport layer cannot provide authentication (e.g. TCP or non-mutual TLS transports).
      • When client mutual TLS authentication is configured this will initially return a non-anonymous Subject based on the TLS certificate presented by the client.
      • Because of the possibility of reauthentication it is also possible for the subject to change.

      Because the subject can change, callers are advised to avoid caching subjects, or decisions derived from them.

      Which principals are present in the returned subject, and what their names look like, depends on the configuration of network and/or authentication filters. In general, routers should be configurable with respect to the principal type when interrogating the returned subject.

      SASL filter placement: This value reflects authentication performed on the virtual cluster filter chain only. "SASL initiator" filters placed on per-route filter chains do not affect the subject returned here — those authenticate the proxy's outbound connection to the upstream cluster, not the client's identity.

      Returns:
      the client subject
    • respondWith

      CloseOrTerminalStage respondWith(org.apache.kafka.common.protocol.ApiMessage body)
      Begins building a router response that delivers the given response body to the client. The runtime provides a response header.
      Parameters:
      body - the response body
      Returns:
      a stage that can optionally close the connection
    • respondWith

      CloseOrTerminalStage respondWith(org.apache.kafka.common.message.ResponseHeaderData header, org.apache.kafka.common.protocol.ApiMessage body)
      Begins building a router response that delivers a synthesised response to the client.
      Parameters:
      header - the response header
      body - the response body
      Returns:
      a stage that can optionally close the connection
    • respondWithError

      CloseOrTerminalStage respondWithError(org.apache.kafka.common.message.RequestHeaderData header, org.apache.kafka.common.protocol.ApiMessage request, org.apache.kafka.common.errors.ApiException exception)
      Begins building a router result that generates an error response for the client. The generated error response is API-specific.
      Parameters:
      header - the request header
      request - the request body
      exception - the exception that triggered the error
      Returns:
      a stage that can optionally close the connection
    • respondWithoutReply

      CloseOrTerminalStage respondWithoutReply()
      Begins building a router result for a fire-and-forget request where no response is delivered to the client (e.g. acks=0 PRODUCE).
      Returns:
      a stage that can optionally close the connection