From 0f7498e5e18d16f87054f6af82b94d58ef4ff515 Mon Sep 17 00:00:00 2001 From: Pablo Carle Date: Tue, 15 Jul 2025 10:18:13 +0200 Subject: [PATCH 1/4] fix issues in gatewayhealthindicator wip Signed-off-by: Pablo Carle --- .../zowe/apiml/GatewayHealthIndicator.java | 23 ++++++++++----- .../config/GatewayHealthIndicator.java | 29 ++++++++++--------- 2 files changed, 32 insertions(+), 20 deletions(-) diff --git a/apiml/src/main/java/org/zowe/apiml/GatewayHealthIndicator.java b/apiml/src/main/java/org/zowe/apiml/GatewayHealthIndicator.java index 463477a9e4..703bed5656 100644 --- a/apiml/src/main/java/org/zowe/apiml/GatewayHealthIndicator.java +++ b/apiml/src/main/java/org/zowe/apiml/GatewayHealthIndicator.java @@ -10,6 +10,7 @@ package org.zowe.apiml; +import com.nimbusds.oauth2.sdk.util.StringUtils; import lombok.RequiredArgsConstructor; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.actuate.health.AbstractHealthIndicator; @@ -20,8 +21,9 @@ import org.springframework.context.event.EventListener; import org.springframework.stereotype.Component; import org.zowe.apiml.message.log.ApimlLogger; -import org.zowe.apiml.message.yaml.YamlMessageServiceInstance; +import org.zowe.apiml.product.compatibility.ApimlHealthCheckHandler; import org.zowe.apiml.product.constants.CoreService; +import org.zowe.apiml.product.logging.annotations.InjectApimlLogger; import org.zowe.apiml.zaas.ZaasServiceAvailableEvent; import java.util.concurrent.atomic.AtomicBoolean; @@ -39,25 +41,26 @@ @RequiredArgsConstructor public class GatewayHealthIndicator extends AbstractHealthIndicator { - private static final ApimlLogger apimlLog = ApimlLogger.of(GatewayHealthIndicator.class, YamlMessageServiceInstance.getInstance()); private final DiscoveryClient discoveryClient; + @InjectApimlLogger + private final ApimlLogger apimlLog = ApimlLogger.empty(); + @Value("${apiml.catalog.serviceId:}") private String apiCatalogServiceId; private AtomicBoolean discoveryAvailable = new AtomicBoolean(false); private AtomicBoolean zaasAvailable = new AtomicBoolean(false); - private AtomicBoolean startedInformationPublished = new AtomicBoolean(false); @Override protected void doHealthCheck(Builder builder) throws Exception { - var anyCatalogIsAvailable = apiCatalogServiceId != null && !apiCatalogServiceId.isEmpty(); - var apiCatalogUp = !this.discoveryClient.getInstances(apiCatalogServiceId).isEmpty(); + var anyCatalogIsAvailable = StringUtils.isNotBlank(apiCatalogServiceId); + var apiCatalogUp = anyCatalogIsAvailable && !this.discoveryClient.getInstances(apiCatalogServiceId).isEmpty(); // Keeping for backwards compatibility, in modulith the amount of gateways is the amount of authentication services available - int gatewayCount = this.discoveryClient.getInstances(CoreService.GATEWAY.getServiceId()).size(); - int zaasCount = gatewayCount; + var gatewayCount = this.discoveryClient.getInstances(CoreService.GATEWAY.getServiceId()).size(); + var zaasCount = gatewayCount; builder.status(toStatus(discoveryAvailable.get() && zaasAvailable.get())) .withDetail(CoreService.DISCOVERY.getServiceId(), toStatus(discoveryAvailable.get()).getCode()) @@ -70,6 +73,12 @@ protected void doHealthCheck(Builder builder) throws Exception { } if (!startedInformationPublished.get() && discoveryAvailable.get() && apiCatalogUp && zaasAvailable.get()) { + onFullyUp(); + } + } + + private void onFullyUp() { + if (!startedInformationPublished.get()) { apimlLog.log("org.zowe.apiml.common.mediationLayerStarted"); startedInformationPublished.set(true); } diff --git a/gateway-service/src/main/java/org/zowe/apiml/gateway/config/GatewayHealthIndicator.java b/gateway-service/src/main/java/org/zowe/apiml/gateway/config/GatewayHealthIndicator.java index 7be21cd967..cc7013c55e 100644 --- a/gateway-service/src/main/java/org/zowe/apiml/gateway/config/GatewayHealthIndicator.java +++ b/gateway-service/src/main/java/org/zowe/apiml/gateway/config/GatewayHealthIndicator.java @@ -10,6 +10,7 @@ package org.zowe.apiml.gateway.config; +import com.nimbusds.oauth2.sdk.util.StringUtils; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.actuate.health.AbstractHealthIndicator; import org.springframework.boot.actuate.health.Health; @@ -18,9 +19,11 @@ import org.springframework.cloud.client.discovery.DiscoveryClient; import org.springframework.stereotype.Component; import org.zowe.apiml.message.log.ApimlLogger; -import org.zowe.apiml.message.yaml.YamlMessageServiceInstance; import org.zowe.apiml.product.compatibility.ApimlHealthCheckHandler; import org.zowe.apiml.product.constants.CoreService; +import org.zowe.apiml.product.logging.annotations.InjectApimlLogger; + +import java.util.concurrent.atomic.AtomicBoolean; import static org.springframework.boot.actuate.health.Status.DOWN; import static org.springframework.boot.actuate.health.Status.UP; @@ -35,11 +38,11 @@ public class GatewayHealthIndicator extends AbstractHealthIndicator { protected final DiscoveryClient discoveryClient; - private String apiCatalogServiceId; + private final String apiCatalogServiceId; + @InjectApimlLogger + private final ApimlLogger apimlLog = ApimlLogger.empty(); - private final ApimlLogger apimlLog = ApimlLogger.of(GatewayHealthIndicator.class, - YamlMessageServiceInstance.getInstance()); - boolean startedInformationPublished = false; + private AtomicBoolean startedInformationPublished = new AtomicBoolean(false); public GatewayHealthIndicator(DiscoveryClient discoveryClient, @Value("${apiml.catalog.serviceId:}") String apiCatalogServiceId) { @@ -49,16 +52,16 @@ public GatewayHealthIndicator(DiscoveryClient discoveryClient, @Override protected void doHealthCheck(Health.Builder builder) { - boolean anyCatalogIsAvailable = apiCatalogServiceId != null && !apiCatalogServiceId.isEmpty(); - boolean apiCatalogUp = !this.discoveryClient.getInstances(apiCatalogServiceId).isEmpty(); + var anyCatalogIsAvailable = StringUtils.isNotBlank(apiCatalogServiceId); + var apiCatalogUp = anyCatalogIsAvailable && !this.discoveryClient.getInstances(apiCatalogServiceId).isEmpty(); // When DS goes 'down' after it was already 'up', the new status is not shown. This is probably feature of // Eureka client which caches the status of services. When DS is down the cache is not refreshed. - boolean discoveryUp = !this.discoveryClient.getInstances(CoreService.DISCOVERY.getServiceId()).isEmpty(); - boolean zaasUp = !this.discoveryClient.getInstances(CoreService.ZAAS.getServiceId()).isEmpty(); + var discoveryUp = !this.discoveryClient.getInstances(CoreService.DISCOVERY.getServiceId()).isEmpty(); + var zaasUp = !this.discoveryClient.getInstances(CoreService.ZAAS.getServiceId()).isEmpty(); - int gatewayCount = this.discoveryClient.getInstances(CoreService.GATEWAY.getServiceId()).size(); - int zaasCount = this.discoveryClient.getInstances(CoreService.ZAAS.getServiceId()).size(); + var gatewayCount = this.discoveryClient.getInstances(CoreService.GATEWAY.getServiceId()).size(); + var zaasCount = this.discoveryClient.getInstances(CoreService.ZAAS.getServiceId()).size(); builder.status(toStatus(discoveryUp)) .withDetail(CoreService.DISCOVERY.getServiceId(), toStatus(discoveryUp).getCode()) @@ -76,9 +79,9 @@ protected void doHealthCheck(Health.Builder builder) { } private void onFullyUp() { - if (!startedInformationPublished) { + if (!startedInformationPublished.get()) { apimlLog.log("org.zowe.apiml.common.mediationLayerStarted"); - startedInformationPublished = true; + startedInformationPublished.set(true); } } From d710a9278ab4ba29bfccb837e75369a36a80da78 Mon Sep 17 00:00:00 2001 From: Pablo Carle Date: Tue, 15 Jul 2025 13:43:34 +0200 Subject: [PATCH 2/4] add test for initialization message Signed-off-by: Pablo Carle --- .../product/logging/ApimlLogInjector.java | 12 +++- .../product/logging/ApimlLogInjectorTest.java | 10 +++- .../zowe/apiml/GatewayHealthIndicator.java | 34 +++++++++-- .../AcceptanceTestWithMockServices.java | 2 +- .../StartupMessageAcceptanceTest.java | 60 +++++++++++++++++++ .../config/GatewayHealthIndicator.java | 9 ++- .../config/GatewayHealthIndicatorTest.java | 2 +- 7 files changed, 114 insertions(+), 15 deletions(-) create mode 100644 apiml/src/test/java/org/zowe/apiml/acceptance/StartupMessageAcceptanceTest.java diff --git a/apiml-utility/src/main/java/org/zowe/apiml/product/logging/ApimlLogInjector.java b/apiml-utility/src/main/java/org/zowe/apiml/product/logging/ApimlLogInjector.java index 88bbec48f6..c254ae6a7f 100644 --- a/apiml-utility/src/main/java/org/zowe/apiml/product/logging/ApimlLogInjector.java +++ b/apiml-utility/src/main/java/org/zowe/apiml/product/logging/ApimlLogInjector.java @@ -14,7 +14,9 @@ import org.zowe.apiml.message.yaml.YamlMessageServiceInstance; import org.zowe.apiml.product.logging.annotations.InjectApimlLogger; import lombok.RequiredArgsConstructor; +import org.springframework.beans.BeansException; import org.springframework.beans.factory.config.BeanPostProcessor; +import org.springframework.context.ApplicationContext; import org.springframework.stereotype.Component; import org.springframework.util.ReflectionUtils; @@ -29,6 +31,8 @@ @RequiredArgsConstructor public class ApimlLogInjector implements BeanPostProcessor { + private final ApplicationContext applicationContext; + @Override public Object postProcessAfterInitialization(@Nonnull Object bean, @Nonnull String beanName) { return bean; @@ -41,7 +45,13 @@ public Object postProcessBeforeInitialization(final Object bean, @Nonnull String // make the field accessible if defined private ReflectionUtils.makeAccessible(field); Class clazz = getClass(bean); - ApimlLogger log = ApimlLogger.of(clazz, YamlMessageServiceInstance.getInstance()); + + ApimlLogger log; + try { + log = applicationContext.getBean(ApimlLogger.class); + } catch (BeansException e) { + log = ApimlLogger.of(clazz, YamlMessageServiceInstance.getInstance()); + } field.set(bean, log); } }); diff --git a/apiml-utility/src/test/java/org/zowe/apiml/product/logging/ApimlLogInjectorTest.java b/apiml-utility/src/test/java/org/zowe/apiml/product/logging/ApimlLogInjectorTest.java index bfae292792..303e72634d 100644 --- a/apiml-utility/src/test/java/org/zowe/apiml/product/logging/ApimlLogInjectorTest.java +++ b/apiml-utility/src/test/java/org/zowe/apiml/product/logging/ApimlLogInjectorTest.java @@ -14,6 +14,7 @@ import org.junit.jupiter.api.extension.ExtendWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.TestConfiguration; +import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Import; import org.springframework.test.context.junit.jupiter.SpringExtension; @@ -47,13 +48,16 @@ private static class TestComponent { @TestConfiguration static class TestConfig { + @Autowired + private ApplicationContext applicationContext; + @Bean - public ApimlLogInjector apimlLogInjector() { - return new ApimlLogInjector(); + ApimlLogInjector apimlLogInjector() { + return new ApimlLogInjector(applicationContext); } @Bean - public TestComponent testComponent() { + TestComponent testComponent() { return new ApimlLogInjectorTest.TestComponent(); } diff --git a/apiml/src/main/java/org/zowe/apiml/GatewayHealthIndicator.java b/apiml/src/main/java/org/zowe/apiml/GatewayHealthIndicator.java index 703bed5656..3e79d24e97 100644 --- a/apiml/src/main/java/org/zowe/apiml/GatewayHealthIndicator.java +++ b/apiml/src/main/java/org/zowe/apiml/GatewayHealthIndicator.java @@ -10,13 +10,14 @@ package org.zowe.apiml; -import com.nimbusds.oauth2.sdk.util.StringUtils; import lombok.RequiredArgsConstructor; +import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.actuate.health.AbstractHealthIndicator; import org.springframework.boot.actuate.health.Health.Builder; import org.springframework.boot.actuate.health.Status; import org.springframework.cloud.client.discovery.DiscoveryClient; +import org.springframework.cloud.netflix.eureka.server.event.EurekaInstanceRegisteredEvent; import org.springframework.cloud.netflix.eureka.server.event.EurekaRegistryAvailableEvent; import org.springframework.context.event.EventListener; import org.springframework.stereotype.Component; @@ -51,12 +52,13 @@ public class GatewayHealthIndicator extends AbstractHealthIndicator { private AtomicBoolean discoveryAvailable = new AtomicBoolean(false); private AtomicBoolean zaasAvailable = new AtomicBoolean(false); + private AtomicBoolean catalogAvailable = new AtomicBoolean(false); private AtomicBoolean startedInformationPublished = new AtomicBoolean(false); @Override protected void doHealthCheck(Builder builder) throws Exception { var anyCatalogIsAvailable = StringUtils.isNotBlank(apiCatalogServiceId); - var apiCatalogUp = anyCatalogIsAvailable && !this.discoveryClient.getInstances(apiCatalogServiceId).isEmpty(); + catalogAvailable.compareAndSet(false, anyCatalogIsAvailable && !this.discoveryClient.getInstances(apiCatalogServiceId).isEmpty()); // Keeping for backwards compatibility, in modulith the amount of gateways is the amount of authentication services available var gatewayCount = this.discoveryClient.getInstances(CoreService.GATEWAY.getServiceId()).size(); @@ -69,29 +71,49 @@ protected void doHealthCheck(Builder builder) throws Exception { .withDetail("zaasCount", zaasCount); if (anyCatalogIsAvailable) { - builder.withDetail(CoreService.API_CATALOG.getServiceId(), toStatus(apiCatalogUp).getCode()); + builder.withDetail(CoreService.API_CATALOG.getServiceId(), toStatus(catalogAvailable.get()).getCode()); } - if (!startedInformationPublished.get() && discoveryAvailable.get() && apiCatalogUp && zaasAvailable.get()) { + if (isFullyUp()) { onFullyUp(); } } + private boolean isFullyUp() { + return !startedInformationPublished.get() && discoveryAvailable.get() && catalogAvailable.get() && zaasAvailable.get(); + } + private void onFullyUp() { - if (!startedInformationPublished.get()) { + if (startedInformationPublished.compareAndSet(false, true)) { apimlLog.log("org.zowe.apiml.common.mediationLayerStarted"); - startedInformationPublished.set(true); } } @EventListener public void onApplicationEvent(ZaasServiceAvailableEvent event) { zaasAvailable.set(true); + if (isFullyUp()) { + onFullyUp(); + } } @EventListener public void onApplicationEvent(EurekaRegistryAvailableEvent event) { discoveryAvailable.set(true); + if (isFullyUp()) { + onFullyUp(); + } + } + + @EventListener + public void onApplicationEvent(EurekaInstanceRegisteredEvent event) { + var instanceInfo = event.getInstanceInfo(); + if (String.valueOf(instanceInfo.getAppName()).equalsIgnoreCase(apiCatalogServiceId)) { + catalogAvailable.set(true); + } + if (isFullyUp()) { + onFullyUp(); + } } boolean isStartedInformationPublished() { diff --git a/apiml/src/test/java/org/zowe/apiml/acceptance/AcceptanceTestWithMockServices.java b/apiml/src/test/java/org/zowe/apiml/acceptance/AcceptanceTestWithMockServices.java index 830d0a44fd..dd28788dd1 100644 --- a/apiml/src/test/java/org/zowe/apiml/acceptance/AcceptanceTestWithMockServices.java +++ b/apiml/src/test/java/org/zowe/apiml/acceptance/AcceptanceTestWithMockServices.java @@ -28,7 +28,7 @@ public class AcceptanceTestWithMockServices extends AcceptanceTestWithBasePath { @Autowired - private ApplicationEventPublisher applicationEventPublisher; + protected ApplicationEventPublisher applicationEventPublisher; @Autowired @Qualifier("applicationRegistry") diff --git a/apiml/src/test/java/org/zowe/apiml/acceptance/StartupMessageAcceptanceTest.java b/apiml/src/test/java/org/zowe/apiml/acceptance/StartupMessageAcceptanceTest.java new file mode 100644 index 0000000000..3d35055c68 --- /dev/null +++ b/apiml/src/test/java/org/zowe/apiml/acceptance/StartupMessageAcceptanceTest.java @@ -0,0 +1,60 @@ +/* + * This program and the accompanying materials are made available under the terms of the + * Eclipse Public License v2.0 which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-v20.html + * + * SPDX-License-Identifier: EPL-2.0 + * + * Copyright Contributors to the Zowe Project. + */ + +package org.zowe.apiml.acceptance; + +import com.netflix.appinfo.InstanceInfo; +import com.netflix.eureka.EurekaServerConfig; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.Timeout; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import org.springframework.cloud.netflix.eureka.server.event.EurekaInstanceRegisteredEvent; +import org.springframework.cloud.netflix.eureka.server.event.EurekaRegistryAvailableEvent; +import org.springframework.test.context.bean.override.mockito.MockitoBean; +import org.zowe.apiml.message.log.ApimlLogger; +import org.zowe.apiml.zaas.ZaasServiceAvailableEvent; + +import java.util.concurrent.TimeUnit; + +import static org.mockito.Mockito.lenient; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.timeout; +import static org.mockito.Mockito.verify; + +@AcceptanceTest +@ExtendWith(MockitoExtension.class) +public class StartupMessageAcceptanceTest extends AcceptanceTestWithMockServices { + + @MockitoBean private ApimlLogger logger; + + @Mock private InstanceInfo instanceInfo; + + @BeforeEach + void setUp() { + lenient().when(instanceInfo.getInstanceId()).thenReturn("apicatalog:localhost:1000"); + lenient().when(instanceInfo.getAppName()).thenReturn("APICATALOG"); + + applicationEventPublisher.publishEvent(new ZaasServiceAvailableEvent("dummy")); + applicationEventPublisher.publishEvent(new EurekaRegistryAvailableEvent(mock(EurekaServerConfig.class))); + applicationEventPublisher.publishEvent(new EurekaInstanceRegisteredEvent(new Object(), instanceInfo, DISCOVERY_PORT, false)); + } + + @Test + @Timeout(unit = TimeUnit.SECONDS, value = 30) + void whenFullyStartedUp_thenEmitMessage() { + + verify(logger, timeout(30 * 1000L)).log("org.zowe.apiml.common.mediationLayerStarted"); + + } + +} diff --git a/gateway-service/src/main/java/org/zowe/apiml/gateway/config/GatewayHealthIndicator.java b/gateway-service/src/main/java/org/zowe/apiml/gateway/config/GatewayHealthIndicator.java index cc7013c55e..ab4028f2a4 100644 --- a/gateway-service/src/main/java/org/zowe/apiml/gateway/config/GatewayHealthIndicator.java +++ b/gateway-service/src/main/java/org/zowe/apiml/gateway/config/GatewayHealthIndicator.java @@ -10,7 +10,7 @@ package org.zowe.apiml.gateway.config; -import com.nimbusds.oauth2.sdk.util.StringUtils; +import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.actuate.health.AbstractHealthIndicator; import org.springframework.boot.actuate.health.Health; @@ -79,12 +79,15 @@ protected void doHealthCheck(Health.Builder builder) { } private void onFullyUp() { - if (!startedInformationPublished.get()) { + if (startedInformationPublished.compareAndSet(false, true)) { apimlLog.log("org.zowe.apiml.common.mediationLayerStarted"); - startedInformationPublished.set(true); } } + boolean isStartedInformationPublished() { + return startedInformationPublished.get(); + } + private Status toStatus(boolean up) { return up ? UP : DOWN; } diff --git a/gateway-service/src/test/java/org/zowe/apiml/gateway/config/GatewayHealthIndicatorTest.java b/gateway-service/src/test/java/org/zowe/apiml/gateway/config/GatewayHealthIndicatorTest.java index 5b6e4ec3ad..0c54c699be 100644 --- a/gateway-service/src/test/java/org/zowe/apiml/gateway/config/GatewayHealthIndicatorTest.java +++ b/gateway-service/src/test/java/org/zowe/apiml/gateway/config/GatewayHealthIndicatorTest.java @@ -106,7 +106,7 @@ void whenHealthRequested_onceLogMessageAboutStartup() { Health.Builder builder = new Health.Builder(); healthIndicator.doHealthCheck(builder); - assertThat(healthIndicator.startedInformationPublished, is(true)); + assertThat(healthIndicator.isStartedInformationPublished(), is(true)); } } } From 2b1c289c139141c4cfafa2ac5818f140ff21f195 Mon Sep 17 00:00:00 2001 From: Pablo Carle Date: Tue, 15 Jul 2025 14:51:55 +0200 Subject: [PATCH 3/4] pr review Signed-off-by: Pablo Carle --- .../org/zowe/apiml/acceptance/StartupMessageAcceptanceTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apiml/src/test/java/org/zowe/apiml/acceptance/StartupMessageAcceptanceTest.java b/apiml/src/test/java/org/zowe/apiml/acceptance/StartupMessageAcceptanceTest.java index 3d35055c68..5efa37caf2 100644 --- a/apiml/src/test/java/org/zowe/apiml/acceptance/StartupMessageAcceptanceTest.java +++ b/apiml/src/test/java/org/zowe/apiml/acceptance/StartupMessageAcceptanceTest.java @@ -53,7 +53,7 @@ void setUp() { @Timeout(unit = TimeUnit.SECONDS, value = 30) void whenFullyStartedUp_thenEmitMessage() { - verify(logger, timeout(30 * 1000L)).log("org.zowe.apiml.common.mediationLayerStarted"); + verify(logger, timeout(30_000)).log("org.zowe.apiml.common.mediationLayerStarted"); } From afda207c8634f49512ff617076f0cd4d00e95034 Mon Sep 17 00:00:00 2001 From: Pablo Carle Date: Tue, 15 Jul 2025 15:10:12 +0200 Subject: [PATCH 4/4] pr review Signed-off-by: Pablo Carle --- apiml/src/main/java/org/zowe/apiml/GatewayHealthIndicator.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apiml/src/main/java/org/zowe/apiml/GatewayHealthIndicator.java b/apiml/src/main/java/org/zowe/apiml/GatewayHealthIndicator.java index 3e79d24e97..e065d1a2eb 100644 --- a/apiml/src/main/java/org/zowe/apiml/GatewayHealthIndicator.java +++ b/apiml/src/main/java/org/zowe/apiml/GatewayHealthIndicator.java @@ -58,7 +58,7 @@ public class GatewayHealthIndicator extends AbstractHealthIndicator { @Override protected void doHealthCheck(Builder builder) throws Exception { var anyCatalogIsAvailable = StringUtils.isNotBlank(apiCatalogServiceId); - catalogAvailable.compareAndSet(false, anyCatalogIsAvailable && !this.discoveryClient.getInstances(apiCatalogServiceId).isEmpty()); + catalogAvailable.set(anyCatalogIsAvailable && !this.discoveryClient.getInstances(apiCatalogServiceId).isEmpty()); // Keeping for backwards compatibility, in modulith the amount of gateways is the amount of authentication services available var gatewayCount = this.discoveryClient.getInstances(CoreService.GATEWAY.getServiceId()).size();