diff --git a/model/infinispan/src/main/java/org/keycloak/connections/infinispan/InfinispanMultiSiteLoadBalancerCheckProvider.java b/model/infinispan/src/main/java/org/keycloak/connections/infinispan/InfinispanMultiSiteLoadBalancerCheckProvider.java deleted file mode 100644 index 704cefde06..0000000000 --- a/model/infinispan/src/main/java/org/keycloak/connections/infinispan/InfinispanMultiSiteLoadBalancerCheckProvider.java +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright 2023 Red Hat, Inc. and/or its affiliates - * and other contributors as indicated by the @author tags. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.keycloak.connections.infinispan; - -import org.infinispan.Cache; -import org.infinispan.factories.ComponentRegistry; -import org.infinispan.persistence.manager.PersistenceManager; -import org.jboss.logging.Logger; -import org.keycloak.health.LoadBalancerCheckProvider; - -import java.util.Objects; - -import static org.keycloak.connections.infinispan.InfinispanConnectionProvider.ALL_CACHES_NAME; - -public class InfinispanMultiSiteLoadBalancerCheckProvider implements LoadBalancerCheckProvider { - private static final Logger LOG = Logger.getLogger(InfinispanMultiSiteLoadBalancerCheckProvider.class); - private final InfinispanConnectionProvider connectionProvider; - - public InfinispanMultiSiteLoadBalancerCheckProvider(InfinispanConnectionProvider connectionProvider) { - Objects.requireNonNull(connectionProvider, "connectionProvider"); - this.connectionProvider = connectionProvider; - } - - /** - * Non-blocking check if all caches and their persistence are available. - *

- * In a situation where any cache's remote cache is unreachable, this will report the "down" to the caller. - * When the remote cache is down, it assumes that it is down for all Keycloak nodes in this site, all incoming - * requests are likely to fail and that a loadbalancer should send traffic to the other site that might be healthy. - *

- * This code is non-blocking as the embedded Infinispan checks the connection to the remote store periodically - * in the background (default: every second). - * See {@link LoadBalancerCheckProvider#isDown()} to read more why this needs to be non-blocking. - * - * @return true if the component is down/unhealthy, false otherwise - */ - @Override - public boolean isDown() { - for (String cacheName : ALL_CACHES_NAME) { - // do not block in cache creation, as this method is required to be non-blocking - Cache cache = connectionProvider.getCache(cacheName, false); - - // check if cache is started - if (cache == null || !cache.getStatus().allowInvocations()) { - LOG.debugf("Cache '%s' is not started yet.", cacheName); - return true; // no need to check other caches - } - - var persistenceManager = ComponentRegistry.componentOf(cache, PersistenceManager.class); - - if (persistenceManager != null && !persistenceManager.isAvailable()) { - LOG.debugf("PersistenceManager for cache '%s' is down.", cacheName); - return true; // no need to check other caches - } - LOG.debugf("Cache '%s' is up.", cacheName); - } - - return false; - } - - @Override - public void close() { - - } -} diff --git a/model/infinispan/src/main/java/org/keycloak/connections/infinispan/InfinispanMultiSiteLoadBalancerCheckProviderFactory.java b/model/infinispan/src/main/java/org/keycloak/connections/infinispan/InfinispanMultiSiteLoadBalancerCheckProviderFactory.java deleted file mode 100644 index f98e24110c..0000000000 --- a/model/infinispan/src/main/java/org/keycloak/connections/infinispan/InfinispanMultiSiteLoadBalancerCheckProviderFactory.java +++ /dev/null @@ -1,101 +0,0 @@ -/* - * Copyright 2023 Red Hat, Inc. and/or its affiliates - * and other contributors as indicated by the @author tags. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.keycloak.connections.infinispan; - -import org.infinispan.factories.ComponentRegistry; -import org.infinispan.persistence.manager.PersistenceManager; -import org.jboss.logging.Logger; -import org.keycloak.Config; -import org.keycloak.common.Profile; -import org.keycloak.health.LoadBalancerCheckProvider; -import org.keycloak.health.LoadBalancerCheckProviderFactory; -import org.keycloak.models.KeycloakSession; -import org.keycloak.models.KeycloakSessionFactory; -import org.keycloak.provider.EnvironmentDependentProviderFactory; - -import static org.keycloak.connections.infinispan.InfinispanConnectionProvider.ALL_CACHES_NAME; - - -public class InfinispanMultiSiteLoadBalancerCheckProviderFactory implements LoadBalancerCheckProviderFactory, EnvironmentDependentProviderFactory { - - private LoadBalancerCheckProvider loadBalancerCheckProvider; - public static final LoadBalancerCheckProvider ALWAYS_HEALTHY = () -> false; - private static final Logger LOG = Logger.getLogger(InfinispanMultiSiteLoadBalancerCheckProviderFactory.class); - - @Override - public LoadBalancerCheckProvider create(KeycloakSession session) { - if (loadBalancerCheckProvider == null) { - InfinispanConnectionProvider infinispanConnectionProvider = session.getProvider(InfinispanConnectionProvider.class); - if (infinispanConnectionProvider == null) { - LOG.warn("InfinispanConnectionProvider is not available. Load balancer check will be always healthy for Infinispan."); - loadBalancerCheckProvider = ALWAYS_HEALTHY; - } else { - loadBalancerCheckProvider = () -> isEmbeddedCachesDown(infinispanConnectionProvider); - } - } - return loadBalancerCheckProvider; - } - - @Override - public void init(Config.Scope config) { - - } - - @Override - public void postInit(KeycloakSessionFactory factory) { - - } - - @Override - public void close() { - - } - - @Override - public String getId() { - return "infinispan-multisite"; - } - - @Override - public boolean isSupported(Config.Scope config) { - return Profile.isFeatureEnabled(Profile.Feature.MULTI_SITE) && !Profile.isFeatureEnabled(Profile.Feature.REMOTE_CACHE); - } - - private boolean isEmbeddedCachesDown(InfinispanConnectionProvider provider) { - return isAnyEmbeddedCachesDown(provider, ALL_CACHES_NAME, LOG); - } - - public static boolean isAnyEmbeddedCachesDown(InfinispanConnectionProvider connectionProvider, String[] cacheNames, Logger logger) { - for (var name : cacheNames) { - var cache = connectionProvider.getCache(name, false); - - // check if cache is started - if (cache == null || !cache.getStatus().allowInvocations()) { - logger.debugf("Cache '%s' is not started yet.", name); - return true; // no need to check other caches - } - - var persistenceManager = ComponentRegistry.componentOf(cache, PersistenceManager.class); - if (persistenceManager != null && !persistenceManager.isAvailable()) { - logger.debugf("Persistence for embedded cache '%s' is down.", name); - return true; // no need to check other caches - } - } - return false; - } -} diff --git a/model/infinispan/src/main/java/org/keycloak/connections/infinispan/remote/RemoteLoadBalancerCheckProviderFactory.java b/model/infinispan/src/main/java/org/keycloak/connections/infinispan/remote/RemoteLoadBalancerCheckProviderFactory.java index d99a4e96ad..aed35900f9 100644 --- a/model/infinispan/src/main/java/org/keycloak/connections/infinispan/remote/RemoteLoadBalancerCheckProviderFactory.java +++ b/model/infinispan/src/main/java/org/keycloak/connections/infinispan/remote/RemoteLoadBalancerCheckProviderFactory.java @@ -20,6 +20,8 @@ package org.keycloak.connections.infinispan.remote; import org.infinispan.client.hotrod.impl.InternalRemoteCache; import org.infinispan.client.hotrod.impl.operations.PingResponse; import org.infinispan.commons.util.concurrent.CompletableFutures; +import org.infinispan.factories.ComponentRegistry; +import org.infinispan.persistence.manager.PersistenceManager; import org.infinispan.util.concurrent.ActionSequencer; import org.jboss.logging.Logger; import org.keycloak.Config; @@ -45,12 +47,11 @@ import java.util.stream.Collectors; import static org.keycloak.connections.infinispan.InfinispanConnectionProvider.CLUSTERED_CACHE_NAMES; import static org.keycloak.connections.infinispan.InfinispanConnectionProvider.LOCAL_CACHE_NAMES; -import static org.keycloak.connections.infinispan.InfinispanMultiSiteLoadBalancerCheckProviderFactory.ALWAYS_HEALTHY; -import static org.keycloak.connections.infinispan.InfinispanMultiSiteLoadBalancerCheckProviderFactory.isAnyEmbeddedCachesDown; public class RemoteLoadBalancerCheckProviderFactory implements LoadBalancerCheckProviderFactory, EnvironmentDependentProviderFactory { private static final int DEFAULT_POLL_INTERVAL = 5000; + private static final LoadBalancerCheckProvider ALWAYS_HEALTHY = () -> false; private static final Logger logger = Logger.getLogger(MethodHandles.lookup().lookupClass()); private volatile int pollIntervalMillis; @@ -135,7 +136,22 @@ public class RemoteLoadBalancerCheckProviderFactory implements LoadBalancerCheck } private boolean isEmbeddedCachesDown() { - return isAnyEmbeddedCachesDown(connectionProvider, LOCAL_CACHE_NAMES, logger); + for (var name : LOCAL_CACHE_NAMES) { + var cache = connectionProvider.getCache(name, false); + + // check if cache is started + if (cache == null || !cache.getStatus().allowInvocations()) { + logger.debugf("Cache '%s' is not started yet.", name); + return true; // no need to check other caches + } + + var persistenceManager = ComponentRegistry.componentOf(cache, PersistenceManager.class); + if (persistenceManager != null && !persistenceManager.isAvailable()) { + logger.debugf("Persistence for embedded cache '%s' is down.", name); + return true; // no need to check other caches + } + } + return false; } private record RemoteCacheCheckList(List list, ActionSequencer sequencer) implements Runnable { diff --git a/model/infinispan/src/main/resources/META-INF/services/org.keycloak.health.LoadBalancerCheckProviderFactory b/model/infinispan/src/main/resources/META-INF/services/org.keycloak.health.LoadBalancerCheckProviderFactory index 4a833b2a91..539d234d54 100644 --- a/model/infinispan/src/main/resources/META-INF/services/org.keycloak.health.LoadBalancerCheckProviderFactory +++ b/model/infinispan/src/main/resources/META-INF/services/org.keycloak.health.LoadBalancerCheckProviderFactory @@ -1,2 +1 @@ -org.keycloak.connections.infinispan.InfinispanMultiSiteLoadBalancerCheckProviderFactory org.keycloak.connections.infinispan.remote.RemoteLoadBalancerCheckProviderFactory \ No newline at end of file