Class VirtualClusterRegistry
- All Implemented Interfaces:
AutoCloseable
This is the single source of truth for which virtual clusters exist and their
current lifecycle state. It does not manage networking, endpoint registration,
metrics, or any Netty infrastructure — those remain with KafkaProxy.
The onVirtualClusterStopped callback notifies the owner (typically KafkaProxy)
when a virtual cluster reaches the terminal VirtualClusterLifecycleState.Stopped
state, allowing the owner to apply proxy-level policy (e.g. serve: none).
During reload, the Draining → Initializing → Serving cycle is managed internally
without involving the callback — reload never reaches Stopped.
Each virtual cluster's per-cluster state machine is a VirtualClusterLifecycle.
-
Constructor Summary
ConstructorsConstructorDescriptionVirtualClusterRegistry(List<VirtualClusterModel> virtualClusterModels, BiFunction<Configuration, String, VirtualClusterModel> rawModelResolver, BiConsumer<String, Optional<Throwable>> onVirtualClusterStopped) Creates a new VirtualClusterRegistry for the given set of virtual clusters. -
Method Summary
Modifier and TypeMethodDescriptionaddVirtualCluster(VirtualClusterModel newModel) Creates aVirtualClusterLifecycleinINITIALIZINGfor the given model.voidclose()Shuts down the lifecycle executor.voidderegisterConnection(String clusterName, ClientConnectionStateMachine ccsm) Decrements the active-connections count forclusterNameif the cluster is no longer known to this registry.voidinitializationFailed(String clusterName, Throwable cause) Signals that the named virtual cluster failed to initialize.voidinitializationSucceeded(String clusterName) Signals that the named virtual cluster initialized successfully.lifecycleFor(String clusterName) Returns the lifecycle for the given virtual cluster name.Returns the model for the given virtual cluster name.booleanregisterConnection(String clusterName, ClientConnectionStateMachine ccsm) Attempts to register a new connection forclusterName.removeVirtualCluster(String clusterName) Drives an existing virtual cluster throughSERVING → DRAINING → STOPPED.resolveModel(Configuration config, String clusterName) Builds aVirtualClusterModelfor the named virtual cluster, dispatched onto the lifecycle thread.Transitions all virtual clusters toward draining/stopped as appropriate for shutdown.Returns the currently-tracked virtual cluster models.
-
Constructor Details
-
VirtualClusterRegistry
public VirtualClusterRegistry(List<VirtualClusterModel> virtualClusterModels, BiFunction<Configuration, String, VirtualClusterModel> rawModelResolver, BiConsumer<String, Optional<Throwable>> onVirtualClusterStopped) Creates a new VirtualClusterRegistry for the given set of virtual clusters.- Parameters:
virtualClusterModels- the complete set of virtual cluster configurationsrawModelResolver- builds aVirtualClusterModelfor a (config, clusterName) pair without any threading concerns. The registry wraps every invocation in a dispatch to the lifecycle executor — seeresolveModel(io.kroxylicious.proxy.config.Configuration, java.lang.String). Captured at construction time so plugin-factory wiring is the responsibility of the registry's owner (typically KafkaProxy), not the registry itself.onVirtualClusterStopped- callback invoked with(clusterName, priorFailureCause)whenever a virtual cluster reaches the terminal Stopped state. The cause is empty for clean stops (e.g. drain completed during shutdown) and present for failure-driven stops. The callback must not throw exceptions.- Throws:
NullPointerException- if any argument is nullIllegalArgumentException- if the list contains duplicate cluster names
-
-
Method Details
-
resolveModel
Builds aVirtualClusterModelfor the named virtual cluster, dispatched onto the lifecycle thread. Used byOperationsPlannerduring reconfigure so each filter'sinitialize()runs on a non-event-loop thread regardless of which thread invokedreconfigure().- Throws:
RuntimeException- the same RuntimeException the underlying resolver threw
-
close
public void close()Shuts down the lifecycle executor. Must be called aftershutdownAllClusters()has drained — that method dispatches close work through the executor, so tearing the executor down first would reject straggling submissions.- Specified by:
closein interfaceAutoCloseable
-
virtualClusterModels
Returns the currently-tracked virtual cluster models. The collection reflects the constructor- supplied models PLUS any added at runtime viaaddVirtualCluster(VirtualClusterModel).Iteration order is unspecified (the backing map is concurrent). Callers that need order-stable output should sort the result themselves.
- Returns:
- weakly-consistent snapshot of currently-tracked virtual cluster models
-
initializationSucceeded
Signals that the named virtual cluster initialized successfully. Transitions the cluster from Initializing to Serving.- Parameters:
clusterName- the virtual cluster name- Throws:
IllegalArgumentException- if no cluster with that name exists
-
initializationFailed
Signals that the named virtual cluster failed to initialize. Transitions the cluster from Initializing to Failed, then immediately to Stopped (no recovery path exists today), and fires theonVirtualClusterStoppedcallback.- Parameters:
clusterName- the virtual cluster namecause- the failure cause- Throws:
IllegalArgumentException- if no cluster with that name exists
-
shutdownAllClusters
Transitions all virtual clusters toward draining/stopped as appropriate for shutdown.- Serving → Draining
- Draining → Draining (a pre-existing drain, e.g. from hot-reload, is left to complete)
- Initializing → Stopped (fires callback with empty cause)
- Failed → Stopped (fires callback with cause)
- Stopped → Stopped (no-op)
-
lifecycleFor
Returns the lifecycle for the given virtual cluster name.- Parameters:
clusterName- the virtual cluster name- Returns:
- the lifecycle, or null if no cluster with that name exists
-
modelFor
Returns the model for the given virtual cluster name.- Parameters:
clusterName- the virtual cluster name- Returns:
- the model, or
nullif no cluster with that name exists
-
registerConnection
Attempts to register a new connection forclusterName.- Returns:
trueiff the cluster is known to this registry AND its lifecycle is in a state that accepts new connections (i.e.SERVING). An unknown cluster is treated as a rejection rather than an error so thatKafkaProxyInitializer's existingfalse → rejectConnectionpath covers both "not serving" and "no such cluster" without depending on the bookkeeping-vs-binding ordering invariant being preserved by future changes.
-
deregisterConnection
Decrements the active-connections count forclusterNameif the cluster is no longer known to this registry. Called from a Netty channel-close listener, which can race against entry removal in a future cleanup-on-Stopped -
removeVirtualCluster
Drives an existing virtual cluster throughSERVING → DRAINING → STOPPED. Invoked byConfigurationReloadOrchestratorfor clusters present in the running configuration but absent in the submitted one.The cluster's entry is not removed from the registry on reaching
Stopped— seeshutdownCluster(String, VirtualClusterLifecycle)for the rationale.- Parameters:
clusterName- the virtual cluster to remove; must name an existing cluster- Returns:
- a future that completes when the cluster has reached
Stopped - Throws:
IllegalArgumentException- ifclusterNamedoes not name a registered cluster
-
addVirtualCluster
Creates aVirtualClusterLifecycleinINITIALIZINGfor the given model. Endpoint binding and the transition toSERVINGare the orchestrator's responsibility — once gateway registration succeeds it callsinitializationSucceeded(String); on failure it callsinitializationFailed(String, Throwable)and rolls back the gateway bindings.If an entry already exists for this name AND its lifecycle is
Stopped, the entry is replaced — this is howReplaceCluster's add half re-establishes the cluster after the remove half drove it toStopped. The retained-Stopped- entry policy (seeshutdownCluster(java.lang.String, io.kroxylicious.proxy.internal.VirtualClusterLifecycle)) interacts with re-add by name reuse, and "replace the dead entry" is the natural reconciliation.- Parameters:
newModel- the model for the new cluster- Returns:
- an already-completed future (the operation is synchronous; the
CompletableFutureshape is preserved for caller symmetry withremoveVirtualCluster(java.lang.String)) - Throws:
IllegalStateException- if an entry already exists AND its lifecycle is in any state OTHER thanStopped— re-adding an actively-serving (or initializing, draining, or failed) cluster would be a contract violation. The exception message names the current state to aid diagnosis.
-