Skip to content

Commit 48e65c4

Browse files
fix: FlagsmithClient.close() doesn't kill polling manager properly (#133)
* Convert to daemon thread and ensure that closing works correctly * Remove unnecessary call to getEnvironmentFlags * Add comment * typo Co-authored-by: Kim Gustyr <[email protected]> --------- Co-authored-by: Kim Gustyr <[email protected]>
1 parent bb939bc commit 48e65c4

File tree

2 files changed

+44
-3
lines changed

2 files changed

+44
-3
lines changed

src/main/java/com/flagsmith/threads/PollingManager.java

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ public PollingManager(FlagsmithClient client, Integer interval) {
3232
* @return
3333
*/
3434
private Thread initializeThread() {
35-
return new Thread() {
35+
Thread thread = new Thread() {
3636
@Override
3737
public void run() {
3838
try {
@@ -45,6 +45,8 @@ public void run() {
4545
}
4646
}
4747
};
48+
thread.setDaemon(true);
49+
return thread;
4850
}
4951

5052
/**
@@ -61,5 +63,10 @@ public void stopPolling() {
6163
internalThread.interrupt();
6264
}
6365

64-
66+
/**
67+
* Get thread status
68+
*/
69+
public Boolean getIsThreadAlive() {
70+
return internalThread.isAlive();
71+
}
6572
}

src/test/java/com/flagsmith/FlagsmithClientTest.java

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,12 @@
77
import static org.junit.jupiter.api.Assertions.assertNull;
88
import static org.junit.jupiter.api.Assertions.assertThrows;
99
import static org.junit.jupiter.api.Assertions.assertTrue;
10+
import static org.junit.jupiter.api.Assertions.assertFalse;
11+
1012

1113
import com.fasterxml.jackson.core.JsonProcessingException;
1214
import com.fasterxml.jackson.core.type.TypeReference;
1315
import com.fasterxml.jackson.databind.JsonNode;
14-
import com.flagsmith.responses.FlagsAndTraitsResponse;
1516
import com.flagsmith.config.FlagsmithCacheConfig;
1617
import com.flagsmith.config.FlagsmithConfig;
1718
import com.flagsmith.exceptions.FlagsmithApiError;
@@ -24,6 +25,7 @@
2425
import com.flagsmith.models.DefaultFlag;
2526
import com.flagsmith.models.Flags;
2627
import com.flagsmith.models.Segment;
28+
import com.flagsmith.responses.FlagsAndTraitsResponse;
2729
import com.flagsmith.threads.PollingManager;
2830
import com.flagsmith.threads.RequestProcessor;
2931

@@ -692,4 +694,36 @@ public void testGetIdentityFlags_UsesDefaultFlags_IfLocalEvaluationEnvironmentNu
692694
assertEquals(identityFlags.getFeatureValue("foo"), DEFAULT_FLAG_VALUE);
693695
assertEquals(identityFlags.isFeatureEnabled("foo"), DEFAULT_FLAG_STATE);
694696
}
697+
698+
@Test
699+
public void testClose() throws FlagsmithApiError, InterruptedException {
700+
// Given
701+
int pollingInterval = 1;
702+
703+
FlagsmithConfig config = FlagsmithConfig
704+
.newBuilder()
705+
.withLocalEvaluation(true)
706+
.withEnvironmentRefreshIntervalSeconds(pollingInterval)
707+
.build();
708+
709+
FlagsmithApiWrapper mockedApiWrapper = mock(FlagsmithApiWrapper.class);
710+
when(mockedApiWrapper.getEnvironment()).thenReturn(FlagsmithTestHelper.environmentModel());
711+
when(mockedApiWrapper.getConfig()).thenReturn(config);
712+
713+
FlagsmithClient client = FlagsmithClient.newBuilder()
714+
.withFlagsmithApiWrapper(mockedApiWrapper)
715+
.withConfiguration(config)
716+
.setApiKey("ser.dummy-key")
717+
.build();
718+
719+
// When
720+
client.close();
721+
722+
// Then
723+
// Since the thread will only stop once it reads the interrupt signal correctly
724+
// on its next polling interval, we need to wait for the polling interval
725+
// to complete before checking the thread has been killed correctly.
726+
Thread.sleep(pollingInterval);
727+
assertFalse(client.getPollingManager().getIsThreadAlive());
728+
}
695729
}

0 commit comments

Comments
 (0)