Interface TopologyService
Routers that need topology information obtain a
TopologyService from
RouterFactoryContext.topologyService() during
RouterFactory.initialize(io.kroxylicious.proxy.router.RouterFactoryContext, C). The runtime creates the
underlying cache on first request. Routers that never call
topologyService() pay no cost.
Discovery methods
The three discovery methods — leaders(java.util.Map<java.lang.String, java.util.Set<java.lang.String>>), coordinators(java.lang.String, byte, java.util.Set<java.lang.String>),
topicNames(java.lang.String, java.util.Set<org.apache.kafka.common.Uuid>) — are async and return self-contained result
objects. They may send requests internally to warm the cache
(METADATA for leaders and topic names, FIND_COORDINATOR for
coordinators). The results are valid immediately upon completion
and do not require further cache queries.
Cache population
The cache is populated as a side effect of responses flowing through the routing pipeline:
- METADATA responses populate partition leaders, replicas, ISR, broker info, and topicId→name mappings.
- FIND_COORDINATOR responses populate coordinator mappings,
using request-side context (keyType, key) carried by the
runtime's
PendingResponse.
By the time a discovery method's CompletionStage
completes, the cache is guaranteed to reflect the response.
Cache scope
The cache is shared per router level (not per connection), so all connections through the same router level share the same topology view. The cache is thread-safe.
Authorization and cache scope
The topology cache is not scoped by authenticated subject. When Kafka brokers filter METADATA responses based on ACLs, different connections may receive different subsets of topics. Because the cache is shared, it converges toward the union of all connections' views: each METADATA response adds or updates entries for topics present in the response, but does not remove entries for topics absent from the response.
This is safe because the cache is a routing optimization, not an access-control mechanism:
- The cache stores where to send requests (partition leaders, coordinator nodes, broker addresses), not whether a client is authorized.
- Backend brokers enforce ACLs on every request. A client that resolves a leader from the cache but lacks permission to produce or fetch will receive an authorization error from the broker, exactly as it would without the proxy.
- Cache misses trigger discovery requests on the current connection's sender, which carries that connection's authentication context. A low-privilege connection's filtered METADATA response adds a subset of entries without corrupting entries populated by other connections.
Router authors must not use the topology cache for
authorization decisions. The cache may contain entries
populated by connections with different privileges. Routers
should use the cache only for routing (leader selection,
coordinator discovery, broker address resolution) and rely on
backend broker ACL enforcement for access control. If a router
needs to make authorization decisions, it should use
RouterContext.authenticatedSubject()
and consult an external authorization service.
Cache consistency and staleness
The cache uses additive semantics: responses add or update entries but never remove entries for topics absent from the response. The cache does not observe topic lifecycle events (deletion, recreation) independently — it only learns about cluster state from responses that flow through the proxy. Stale entries can therefore persist, for example partition leaders for a topic that has been deleted and recreated with different partition assignments.
Staleness is safe because the cache is a routing
optimization, not an authoritative source of cluster state.
Stale routing decisions (including incorrect fan-out grouping)
produce broker error codes (NOT_LEADER_OR_FOLLOWER,
UNKNOWN_TOPIC_OR_PARTITION), never silent misdirection
or data corruption — the broker validates every request against
its own authoritative state. Routers should treat these errors
as staleness indicators and call invalidateRoute(java.lang.String) to
trigger cache repopulation from subsequent responses.
-
Method Summary
Modifier and TypeMethodDescriptionbrokerInfo(VirtualNode node) Returns broker metadata (host, port, rack) for a virtual node, or empty if not cached.coordinators(String route, byte keyType, Set<String> keys) Discovers coordinators for the given keys on the given route, sending METADATA (if needed) then FIND_COORDINATOR.voidinvalidateRoute(String route) Coarse invalidation: clears all partition info, coordinators, broker info, and topic ID to name mappings for a route.Discovers partition leaders for the given topics on the given routes, sending METADATA requests as needed.partitionInfo(String topicName, int partitionIndex) Returns full partition info (leader, replicas, ISR) for a topic-partition, or empty if not cached.CompletionStage<Map<org.apache.kafka.common.Uuid, String>> topicNames(String route, Set<org.apache.kafka.common.Uuid> topicIds) Resolves topic IDs to topic names for a given route, batching cache misses into a single METADATA request.
-
Method Details
-
leaders
Discovers partition leaders for the given topics on the given routes, sending METADATA requests as needed. Uncached topics are batched into one METADATA request per route.The returned
PartitionLeadersis a self-contained snapshot — callers should use it directly rather than querying the cache separately.- Parameters:
topicsByRoute- map from route name to set of topic names- Returns:
- a stage that completes with the discovered leaders
-
coordinators
Discovers coordinators for the given keys on the given route, sending METADATA (if needed) then FIND_COORDINATOR. Supports batched lookup matching the FIND_COORDINATOR v4+ protocol.The returned
Coordinatorsis a self-contained snapshot — callers should use it directly rather than querying the cache separately.- Parameters:
route- the route namekeyType- 0 for group, 1 for transactionkeys- the group or transaction IDs to discover- Returns:
- a stage that completes with the discovered coordinators
-
topicNames
CompletionStage<Map<org.apache.kafka.common.Uuid,String>> topicNames(String route, Set<org.apache.kafka.common.Uuid> topicIds) Resolves topic IDs to topic names for a given route, batching cache misses into a single METADATA request.The route parameter is required because per-route filter chains can transform topic names differently — the same cluster-level topic ID can map to different router-visible names on different routes.
Returns a map containing an entry for each topic ID that was successfully resolved. Topic IDs that could not be resolved (e.g. deleted topics) are absent from the returned map.
- Parameters:
route- the route to resolve names fortopicIds- the topic IDs to resolve- Returns:
- a stage that completes with the resolved mappings
-
partitionInfo
Returns full partition info (leader, replicas, ISR) for a topic-partition, or empty if not cached.This is a supplementary lookup for use cases like follower-fetch / AZ-aware routing where the router needs replica and rack information beyond what
PartitionLeadersprovides. If this returns empty, the router can fall back to the leader fromPartitionLeaders.- Parameters:
topicName- the topic namepartitionIndex- the partition index- Returns:
- the partition info, or empty if not cached
-
brokerInfo
Returns broker metadata (host, port, rack) for a virtual node, or empty if not cached.- Parameters:
node- the virtual node- Returns:
- the broker info, or empty if not cached
-
invalidateRoute
Coarse invalidation: clears all partition info, coordinators, broker info, and topic ID to name mappings for a route.Topic ID to name mappings for the route are also cleared, because per-route filter chains can present different names for the same underlying cluster topic.
Called by the router when it observes staleness indicators (e.g.
NOT_LEADER_OR_FOLLOWER,NOT_COORDINATOR) in responses. No background refresh is fired — the client drives the refresh via its own METADATA request, which repopulates the cache as a side effect.- Parameters:
route- the route to invalidate
-