Skip to content

Commit 7016ea5

Browse files
authored
fix: periodically update GW url (#1817)
* periodically update GW url Signed-off-by: achmelo <a.chmelo@gmail.com> * copy pluginDefinition.json Signed-off-by: achmelo <a.chmelo@gmail.com> * listen on spring cloud heartbeat Signed-off-by: achmelo <a.chmelo@gmail.com> * revert scheduling Signed-off-by: achmelo <a.chmelo@gmail.com> * fully initialize apicatalog only once Signed-off-by: achmelo <a.chmelo@gmail.com>
1 parent 9b582a1 commit 7016ea5

File tree

9 files changed

+78
-82
lines changed

9 files changed

+78
-82
lines changed

api-catalog-package/build.gradle

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ task packageApiCatalog(type: Zip) {
1919

2020
into('/') {
2121
from "$resourceDir/manifest.yaml"
22+
from "$resourceDir/pluginDefinition.json"
2223
}
2324

2425
into('plugin/') {

api-catalog-services/src/main/java/org/zowe/apiml/apicatalog/services/status/listeners/GatewayLookupEventListener.java

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,16 @@
99
*/
1010
package org.zowe.apiml.apicatalog.services.status.listeners;
1111

12-
import org.zowe.apiml.apicatalog.instance.InstanceInitializeService;
13-
import org.zowe.apiml.product.gateway.GatewayLookupCompleteEvent;
14-
import org.zowe.apiml.product.registry.CannotRegisterServiceException;
1512
import lombok.RequiredArgsConstructor;
1613
import org.springframework.context.event.EventListener;
1714
import org.springframework.core.Ordered;
1815
import org.springframework.core.annotation.Order;
1916
import org.springframework.stereotype.Component;
17+
import org.zowe.apiml.apicatalog.instance.InstanceInitializeService;
18+
import org.zowe.apiml.product.gateway.GatewayLookupCompleteEvent;
19+
import org.zowe.apiml.product.registry.CannotRegisterServiceException;
20+
21+
import java.util.concurrent.atomic.AtomicBoolean;
2022

2123
/**
2224
* This class fires on GatewayLookupCompleteEvent event
@@ -28,14 +30,13 @@
2830
public class GatewayLookupEventListener {
2931

3032
private final InstanceInitializeService instanceInitializeService;
33+
private final AtomicBoolean hasRun = new AtomicBoolean(false);
3134

32-
/**
33-
* Retrieves and registers all instances known to Eureka
34-
*
35-
* @param event Spring event
36-
*/
37-
@EventListener
38-
public void onApplicationEvent(GatewayLookupCompleteEvent event) throws CannotRegisterServiceException {
39-
instanceInitializeService.retrieveAndRegisterAllInstancesWithCatalog();
35+
@EventListener(GatewayLookupCompleteEvent.class)
36+
public void onApplicationEvent() throws CannotRegisterServiceException {
37+
if (!hasRun.get()) {
38+
hasRun.set(true);
39+
instanceInitializeService.retrieveAndRegisterAllInstancesWithCatalog();
40+
}
4041
}
4142
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
/*
2+
* This program and the accompanying materials are made available under the terms of the
3+
* Eclipse Public License v2.0 which accompanies this distribution, and is available at
4+
* https://www.eclipse.org/legal/epl-v20.html
5+
*
6+
* SPDX-License-Identifier: EPL-2.0
7+
*
8+
* Copyright Contributors to the Zowe Project.
9+
*/
10+
package org.zowe.apiml.apicatalog.services.status.listeners;
11+
12+
import org.junit.jupiter.api.Test;
13+
import org.zowe.apiml.apicatalog.instance.InstanceInitializeService;
14+
15+
import static org.mockito.Mockito.*;
16+
17+
class GatewayLookupEventListenerTest {
18+
19+
@Test
20+
void retrieveAndRegisterAllInstancesWithCatalog_onlyOnce() throws Exception {
21+
InstanceInitializeService instanceInitializeService = mock(InstanceInitializeService.class);
22+
GatewayLookupEventListener gatewayLookupEventListener = new GatewayLookupEventListener(instanceInitializeService);
23+
for (int i = 0; i < 10; i++) {
24+
gatewayLookupEventListener.onApplicationEvent();
25+
}
26+
verify(instanceInitializeService, times(1)).retrieveAndRegisterAllInstancesWithCatalog();
27+
}
28+
29+
30+
}

apiml-common/build.gradle

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ dependencies {
1010
compile libraries.janino
1111
compile libraries.xstream
1212

13+
implementation libraries.spring_cloud_commons
1314

1415
compileOnly libraries.spring_boot_configuration_processor
1516
compileOnly libraries.lombok

apiml-common/src/main/java/org/zowe/apiml/product/gateway/GatewayInstanceInitializer.java

Lines changed: 6 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -9,16 +9,16 @@
99
*/
1010
package org.zowe.apiml.product.gateway;
1111

12-
import org.zowe.apiml.product.constants.CoreService;
13-
import org.zowe.apiml.product.instance.InstanceInitializationException;
14-
import org.zowe.apiml.product.instance.lookup.InstanceLookupExecutor;
1512
import com.netflix.appinfo.InstanceInfo;
1613
import lombok.RequiredArgsConstructor;
1714
import lombok.extern.slf4j.Slf4j;
18-
import org.springframework.boot.context.event.ApplicationReadyEvent;
15+
import org.springframework.cloud.client.discovery.event.HeartbeatEvent;
1916
import org.springframework.context.ApplicationEventPublisher;
2017
import org.springframework.context.event.EventListener;
2118
import org.zowe.apiml.message.log.ApimlLogger;
19+
import org.zowe.apiml.product.constants.CoreService;
20+
import org.zowe.apiml.product.instance.InstanceInitializationException;
21+
import org.zowe.apiml.product.instance.lookup.InstanceLookupExecutor;
2222
import org.zowe.apiml.product.logging.annotations.InjectApimlLogger;
2323

2424
import java.net.URI;
@@ -36,7 +36,7 @@ public class GatewayInstanceInitializer {
3636
private final GatewayClient gatewayClient;
3737

3838
@InjectApimlLogger
39-
private ApimlLogger apimlLog = ApimlLogger.empty();
39+
private final ApimlLogger apimlLog = ApimlLogger.empty();
4040

4141
private GatewayConfigProperties process(InstanceInfo instanceInfo) {
4242
try {
@@ -53,15 +53,8 @@ private GatewayConfigProperties process(InstanceInfo instanceInfo) {
5353

5454
}
5555

56-
/**
57-
* EventListener method that starts the lookup for Gateway
58-
* Listens for {@link ApplicationReadyEvent} to start the {@link InstanceLookupExecutor} and provides the processing logic for the executor
59-
*/
60-
@EventListener(ApplicationReadyEvent.class)
56+
@EventListener(HeartbeatEvent.class)
6157
public void init() {
62-
if (gatewayClient.isInitialized()) {
63-
return;
64-
}
6558

6659
log.info("GatewayInstanceInitializer starting asynchronous initialization of Gateway configuration");
6760

apiml-common/src/main/java/org/zowe/apiml/product/instance/lookup/InstanceLookupExecutor.java

Lines changed: 13 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -9,17 +9,14 @@
99
*/
1010
package org.zowe.apiml.product.instance.lookup;
1111

12-
import org.zowe.apiml.product.instance.InstanceNotFoundException;
1312
import com.netflix.appinfo.InstanceInfo;
1413
import com.netflix.discovery.EurekaClient;
1514
import com.netflix.discovery.shared.Application;
1615
import lombok.RequiredArgsConstructor;
1716
import lombok.extern.slf4j.Slf4j;
17+
import org.zowe.apiml.product.instance.InstanceNotFoundException;
1818

1919
import java.util.List;
20-
import java.util.concurrent.Executors;
21-
import java.util.concurrent.ScheduledExecutorService;
22-
import java.util.concurrent.TimeUnit;
2320
import java.util.function.BiConsumer;
2421
import java.util.function.Consumer;
2522

@@ -31,19 +28,6 @@
3128
public class InstanceLookupExecutor {
3229

3330
private final EurekaClient eurekaClient;
34-
private final ScheduledExecutorService executorService =
35-
Executors.newSingleThreadScheduledExecutor(r -> new Thread(r, "InstanceLookupExecutor-Thread"));
36-
private final int initialDelay;
37-
private final int period;
38-
39-
/**
40-
* Constructor with predefined initial delay of 100ms and retry frequency of 5000ms
41-
*
42-
* @param eurekaClient EurekaClient to use for search
43-
*/
44-
public InstanceLookupExecutor(EurekaClient eurekaClient) {
45-
this(eurekaClient, 100, 5000);
46-
}
4731

4832
private InstanceInfo findEurekaInstance(String serviceId) {
4933
Application application = eurekaClient.getApplication(serviceId);
@@ -71,25 +55,19 @@ public void run(String serviceId,
7155
BiConsumer<Exception, Boolean> handleFailureConsumer) {
7256
log.debug("Started instance finder");
7357

74-
executorService.scheduleAtFixedRate(
75-
() -> {
76-
try {
77-
InstanceInfo instanceInfo = findEurekaInstance(serviceId);
78-
log.debug("App found {}", instanceInfo.getAppName());
58+
try {
59+
InstanceInfo instanceInfo = findEurekaInstance(serviceId);
60+
log.debug("App found {}", instanceInfo.getAppName());
7961

80-
action.accept(instanceInfo);
81-
executorService.shutdownNow();
82-
} catch (InstanceNotFoundException | RetryException e) {
83-
log.debug(e.getMessage());
84-
handleFailureConsumer.accept(e, false);
85-
} catch (Exception e) {
86-
executorService.shutdownNow();
87-
handleFailureConsumer.accept(e, true);
88-
log.debug("Unexpected exception while retrieving '{}' service from Eureka", serviceId);
89-
}
62+
action.accept(instanceInfo);
63+
} catch (InstanceNotFoundException | RetryException e) {
64+
log.debug(e.getMessage());
65+
handleFailureConsumer.accept(e, false);
66+
} catch (Exception e) {
67+
handleFailureConsumer.accept(e, true);
68+
log.debug("Unexpected exception while retrieving '{}' service from Eureka", serviceId);
69+
}
9070

91-
},
92-
initialDelay, period, TimeUnit.MILLISECONDS
93-
);
9471
}
72+
9573
}

apiml-common/src/test/java/org/zowe/apiml/product/gateway/GatewayInstanceInitializerTest.java

Lines changed: 7 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,6 @@
99
*/
1010
package org.zowe.apiml.product.gateway;
1111

12-
import org.zowe.apiml.product.constants.CoreService;
13-
import org.zowe.apiml.product.instance.lookup.InstanceLookupExecutor;
1412
import com.netflix.appinfo.InstanceInfo;
1513
import com.netflix.discovery.EurekaClient;
1614
import com.netflix.discovery.shared.Application;
@@ -23,14 +21,14 @@
2321
import org.springframework.context.annotation.Bean;
2422
import org.springframework.context.annotation.Configuration;
2523
import org.springframework.test.context.junit.jupiter.SpringExtension;
24+
import org.zowe.apiml.product.constants.CoreService;
25+
import org.zowe.apiml.product.instance.lookup.InstanceLookupExecutor;
2626

2727
import java.util.Collections;
2828

2929
import static java.time.Duration.ofMillis;
30-
import static org.junit.jupiter.api.Assertions.assertEquals;
31-
import static org.junit.jupiter.api.Assertions.assertNotNull;
32-
import static org.junit.jupiter.api.Assertions.assertTimeout;
33-
import static org.mockito.Mockito.*;
30+
import static org.junit.jupiter.api.Assertions.*;
31+
import static org.mockito.Mockito.when;
3432

3533
@ExtendWith(SpringExtension.class)
3634
class GatewayInstanceInitializerTest {
@@ -62,9 +60,9 @@ void testInit() {
6260
when(
6361
eurekaClient.getApplication(SERVICE_ID)
6462
).thenReturn(application);
65-
63+
6664
gatewayInstanceInitializer.init();
67-
65+
6866
while (!gatewayClient.isInitialized()) ;
6967
});
7068

@@ -77,9 +75,6 @@ void testInit() {
7775
@Configuration
7876
static class TestConfig {
7977

80-
private static final int INITIAL_DELAY = 1;
81-
private static final int PERIOD = 10;
82-
8378
@MockBean
8479
private EurekaClient eurekaClient;
8580

@@ -91,9 +86,7 @@ public GatewayClient gatewayClient() {
9186
@Bean
9287
public InstanceLookupExecutor instanceLookupExecutor() {
9388
return new InstanceLookupExecutor(
94-
eurekaClient,
95-
INITIAL_DELAY,
96-
PERIOD
89+
eurekaClient
9790
);
9891
}
9992

apiml-common/src/test/java/org/zowe/apiml/product/instance/lookup/InstanceLookupExecutorTest.java

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,6 @@
99
*/
1010
package org.zowe.apiml.product.instance.lookup;
1111

12-
import org.zowe.apiml.product.constants.CoreService;
13-
import org.zowe.apiml.product.instance.InstanceInitializationException;
14-
import org.zowe.apiml.product.instance.InstanceNotFoundException;
1512
import com.netflix.appinfo.InstanceInfo;
1613
import com.netflix.discovery.EurekaClient;
1714
import com.netflix.discovery.shared.Application;
@@ -20,6 +17,9 @@
2017
import org.junit.jupiter.api.extension.ExtendWith;
2118
import org.mockito.Mock;
2219
import org.mockito.junit.jupiter.MockitoExtension;
20+
import org.zowe.apiml.product.constants.CoreService;
21+
import org.zowe.apiml.product.instance.InstanceInitializationException;
22+
import org.zowe.apiml.product.instance.InstanceNotFoundException;
2323

2424
import java.util.Collections;
2525
import java.util.HashMap;
@@ -33,8 +33,6 @@
3333
@ExtendWith(MockitoExtension.class)
3434
class InstanceLookupExecutorTest {
3535

36-
private static final int INITIAL_DELAY = 1;
37-
private static final int PERIOD = 10;
3836
private static final String SERVICE_ID = CoreService.API_CATALOG.getServiceId();
3937

4038
@Mock
@@ -49,7 +47,7 @@ class InstanceLookupExecutorTest {
4947

5048
@BeforeEach
5149
void setUp() {
52-
instanceLookupExecutor = new InstanceLookupExecutor(eurekaClient, INITIAL_DELAY, PERIOD);
50+
instanceLookupExecutor = new InstanceLookupExecutor(eurekaClient);
5351
instances = Collections.singletonList(
5452
getInstance(SERVICE_ID));
5553
latch = new CountDownLatch(1);
@@ -154,9 +152,9 @@ private InstanceInfo getInstance(String serviceId) {
154152
}
155153

156154
InstanceInfo createInstance(String serviceId, String instanceId,
157-
InstanceInfo.InstanceStatus status,
158-
InstanceInfo.ActionType actionType,
159-
HashMap<String, String> metadata) {
155+
InstanceInfo.InstanceStatus status,
156+
InstanceInfo.ActionType actionType,
157+
HashMap<String, String> metadata) {
160158
return new InstanceInfo(
161159
instanceId,
162160
serviceId.toUpperCase(),

gradle/versions.gradle

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ ext {
7676
spring_cloud_starter_eureka : "org.springframework.cloud:spring-cloud-starter-netflix-eureka-client:${springCloudVersion}",
7777
spring_cloud_starter_ribbon : "org.springframework.cloud:spring-cloud-starter-netflix-ribbon:${springCloudVersion}",
7878
spring_cloud_starter_hystrix : "org.springframework.cloud:spring-cloud-starter-netflix-hystrix:${springCloudVersion}",
79+
spring_cloud_commons : "org.springframework.cloud:spring-cloud-commons:${springCloudVersion}",
7980

8081
spring_security_config : "org.springframework.security:spring-security-config:${springSecurityVersion}",
8182
spring_security_core : "org.springframework.security:spring-security-core:${springSecurityVersion}",

0 commit comments

Comments
 (0)