Skip to content

Commit 6f95bd3

Browse files
authored
Merge pull request #1569 from OlgaMaciaszek/2.x-check-current-instance-status-before-update
Check current instance status before update.
2 parents 85f2837 + e715fad commit 6f95bd3

File tree

7 files changed

+103
-18
lines changed

7 files changed

+103
-18
lines changed

.github/workflows/nebula-ci.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,14 +21,14 @@ jobs:
2121
uses: actions/setup-java@v1
2222
with:
2323
java-version: ${{ matrix.java }}
24-
- uses: actions/cache@v1
24+
- uses: actions/cache@v4
2525
id: gradle-cache
2626
with:
2727
path: ~/.gradle/caches
2828
key: ${{ runner.os }}-gradle-${{ hashFiles('**/gradle/dependency-locks/*.lockfile') }}
2929
restore-keys: |
3030
- ${{ runner.os }}-gradle-
31-
- uses: actions/cache@v1
31+
- uses: actions/cache@v4
3232
id: gradle-wrapper-cache
3333
with:
3434
path: ~/.gradle/wrapper

.github/workflows/nebula-publish.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,14 @@ jobs:
1717
uses: actions/setup-java@v1
1818
with:
1919
java-version: 11
20-
- uses: actions/cache@v1
20+
- uses: actions/cache@v4
2121
id: gradle-cache
2222
with:
2323
path: ~/.gradle/caches
2424
key: ${{ runner.os }}-gradle-${{ hashFiles('**/gradle/dependency-locks/*.lockfile') }}
2525
restore-keys: |
2626
- ${{ runner.os }}-gradle-
27-
- uses: actions/cache@v1
27+
- uses: actions/cache@v4
2828
id: gradle-wrapper-cache
2929
with:
3030
path: ~/.gradle/wrapper

.github/workflows/nebula-snapshot.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,13 @@ jobs:
1717
uses: actions/setup-java@v1
1818
with:
1919
java-version: 11
20-
- uses: actions/cache@v2
20+
- uses: actions/cache@v4
2121
id: gradle-cache
2222
with:
2323
path: |
2424
~/.gradle/caches
2525
key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle') }}
26-
- uses: actions/cache@v2
26+
- uses: actions/cache@v4
2727
id: gradle-wrapper-cache
2828
with:
2929
path: |

eureka-client/src/main/java/com/netflix/appinfo/ApplicationInfoManager.java

Lines changed: 35 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@
4141
* </p>
4242
*
4343
*
44-
* @author Karthik Ranganathan, Greg Kim
44+
* @author Karthik Ranganathan, Greg Kim, Olga Maciaszek-Sharma
4545
*
4646
*/
4747
@Singleton
@@ -171,13 +171,29 @@ public synchronized void setInstanceStatus(InstanceStatus status) {
171171

172172
InstanceStatus prev = instanceInfo.setStatus(next);
173173
if (prev != null) {
174-
for (StatusChangeListener listener : listeners.values()) {
175-
try {
176-
listener.notify(new StatusChangeEvent(prev, next));
177-
} catch (Exception e) {
178-
logger.warn("failed to notify listener: {}", listener.getId(), e);
179-
}
180-
}
174+
notifyListeners(prev, next);
175+
}
176+
}
177+
178+
/**
179+
* Set the status of this instance only if the current status equals expected status
180+
* in order to avoid concurrent modification.
181+
* Application can use this to indicate whether it is ready to receive traffic.
182+
* Setting the status here also notifies all registered listeners
183+
* of a status change event.
184+
*
185+
* @param expectedStatus expected current Status of the instance
186+
* @param updateStatus Status of the instance to be set
187+
*/
188+
public synchronized void setInstanceStatus(InstanceStatus expectedStatus, InstanceStatus updateStatus) {
189+
InstanceStatus next = instanceStatusMapper.map(updateStatus);
190+
if (next == null) {
191+
return;
192+
}
193+
194+
InstanceStatus prev = instanceInfo.setStatus(expectedStatus, next);
195+
if (prev != null) {
196+
notifyListeners(prev, next);
181197
}
182198
}
183199

@@ -261,6 +277,17 @@ public void refreshLeaseInfoIfRequired() {
261277
}
262278
}
263279

280+
private void notifyListeners(InstanceStatus prev, InstanceStatus next) {
281+
for (StatusChangeListener listener : listeners.values()) {
282+
try {
283+
listener.notify(new StatusChangeEvent(prev, next));
284+
}
285+
catch (Exception e) {
286+
logger.warn("failed to notify listener: {}", listener.getId(), e);
287+
}
288+
}
289+
}
290+
264291
public static interface StatusChangeListener {
265292
String getId();
266293

eureka-client/src/main/java/com/netflix/appinfo/InstanceInfo.java

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@
2929
import com.fasterxml.jackson.annotation.JsonProperty;
3030
import com.fasterxml.jackson.annotation.JsonRootName;
3131
import com.netflix.appinfo.providers.Archaius1VipAddressResolver;
32-
import com.netflix.appinfo.providers.EurekaConfigBasedInstanceInfoProvider;
3332
import com.netflix.appinfo.providers.VipAddressResolver;
3433
import com.netflix.discovery.converters.Auto;
3534
import com.netflix.discovery.converters.EurekaJacksonCodec.InstanceInfoSerializer;
@@ -48,7 +47,7 @@
4847
* serialized as specified by the <code>@Serializer</code>.
4948
* </p>
5049
*
51-
* @author Karthik Ranganathan, Greg Kim
50+
* @author Karthik Ranganathan, Greg Kim, Olga Maciaszek-Sharma
5251
*/
5352
@Serializer("com.netflix.discovery.converters.EntityBodyConverter")
5453
@XStreamAlias("instance")
@@ -1173,6 +1172,21 @@ public synchronized InstanceStatus setStatus(InstanceStatus status) {
11731172
return null;
11741173
}
11751174

1175+
/**
1176+
* Set the status for this instance only when the current status matches the expected status.
1177+
*
1178+
* @param expected status for this instance.
1179+
* @param status status to set for this instance.
1180+
* @return the prev status if a different status from the current was set, null otherwise
1181+
*/
1182+
public synchronized InstanceStatus setStatus(InstanceStatus expected, InstanceStatus status) {
1183+
InstanceStatus prev = this.status;
1184+
if (expected == null || !expected.equals(prev)) {
1185+
return null;
1186+
}
1187+
return setStatus(status);
1188+
}
1189+
11761190
/**
11771191
* Set the status for this instance without updating the dirty timestamp.
11781192
*

eureka-client/src/main/java/com/netflix/discovery/DiscoveryClient.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1380,16 +1380,17 @@ void refreshInstanceInfo() {
13801380
applicationInfoManager.refreshDataCenterInfoIfRequired();
13811381
applicationInfoManager.refreshLeaseInfoIfRequired();
13821382

1383+
InstanceStatus current = instanceInfo.getStatus();
13831384
InstanceStatus status;
13841385
try {
1385-
status = getHealthCheckHandler().getStatus(instanceInfo.getStatus());
1386+
status = getHealthCheckHandler().getStatus(current);
13861387
} catch (Exception e) {
13871388
logger.warn("Exception from healthcheckHandler.getStatus, setting status to DOWN", e);
13881389
status = InstanceStatus.DOWN;
13891390
}
13901391

13911392
if (null != status) {
1392-
applicationInfoManager.setInstanceStatus(status);
1393+
applicationInfoManager.setInstanceStatus(current, status);
13931394
}
13941395
}
13951396

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
package com.netflix.appinfo;
2+
3+
import com.netflix.discovery.util.InstanceInfoGenerator;
4+
import org.junit.Test;
5+
6+
import static org.assertj.core.api.Assertions.assertThat;
7+
8+
/**
9+
* @author Olga Maciaszek-Sharma
10+
*/
11+
public class InstanceInfoUnitTest {
12+
13+
@Test
14+
public void testInstanceStatusUpdated() {
15+
InstanceInfo instanceInfo = InstanceInfoGenerator.takeOne();
16+
17+
instanceInfo.setStatus(InstanceInfo.InstanceStatus.UP,
18+
InstanceInfo.InstanceStatus.OUT_OF_SERVICE);
19+
20+
assertThat(instanceInfo.getStatus()).isEqualTo(InstanceInfo.InstanceStatus.OUT_OF_SERVICE);
21+
}
22+
23+
@Test
24+
public void testInstanceStatusNotUpdatedWhenExpectedStatusNotMatched() {
25+
InstanceInfo instanceInfo = InstanceInfoGenerator.takeOne();
26+
27+
instanceInfo.setStatus(InstanceInfo.InstanceStatus.DOWN,
28+
InstanceInfo.InstanceStatus.OUT_OF_SERVICE);
29+
30+
assertThat(instanceInfo.getStatus()).isEqualTo(InstanceInfo.InstanceStatus.UP);
31+
}
32+
33+
@Test
34+
public void testInstanceStatusNotUpdatedWhenExpectedStatusNull() {
35+
InstanceInfo instanceInfo = InstanceInfoGenerator.takeOne();
36+
37+
instanceInfo.setStatus(null,
38+
InstanceInfo.InstanceStatus.OUT_OF_SERVICE);
39+
40+
assertThat(instanceInfo.getStatus()).isEqualTo(InstanceInfo.InstanceStatus.UP);
41+
}
42+
43+
}

0 commit comments

Comments
 (0)