Interface RouterContext
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 Summary
Modifier and TypeMethodDescriptionReturns a virtual node that, when passed tosendRequest(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.Returns the client subject.nodeForId(int virtualNodeId) Converts an integer node ID from a protocol response body into aVirtualNode.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.respondWith(org.apache.kafka.common.protocol.ApiMessage body) Begins building a router response that delivers the given response body to the client.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.Begins building a router result for a fire-and-forget request where no response is delivered to the client (e.g. acks=0PRODUCE).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.Returns the unique identifier for the current proxy session.Returns the virtual node of the broker that the client connected to.
-
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
Returns a virtual node that, when passed tosendRequest(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
Converts an integer node ID from a protocol response body into aVirtualNode.This is the bridge between the Kafka wire protocol (which uses integer node IDs) and the
VirtualNodeAPI. Routers need this when interpreting node IDs in protocol messages — for example, broker node IDs inMETADATAresponses, coordinator node IDs inFIND_COORDINATORresponses, 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
nodecan be:- A value obtained from
virtualNode()— sends to the broker the client connected to - A value obtained from
anyNode(String)— sends to an arbitrary broker on a route - A value obtained from
nodeForId(int)— sends to a broker whose ID was learned from a protocol response - A value obtained from
TopologyServicediscovery methods (e.g.PartitionLeaders.leaderOf)
- Parameters:
node- the virtual node of the target brokerheader- the request headerrequest- 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)
- A value obtained from
-
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 emptyprincipalsset) 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
Subjectbased 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
- This will return an anonymous
-
respondWith
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 headerbody- 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 headerrequest- the request bodyexception- 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=0PRODUCE).- Returns:
- a stage that can optionally close the connection
-