Skip to content

Commit 9f43e80

Browse files
authored
feat: use descriptive thread names (#1704)
* added a configurable thread factory to allow naming of threads Signed-off-by: jarebudev <23311805+jarebudev@users.noreply.github.com> * tidy up Signed-off-by: jarebudev <23311805+jarebudev@users.noreply.github.com> --------- Signed-off-by: jarebudev <23311805+jarebudev@users.noreply.github.com>
1 parent 6a50468 commit 9f43e80

File tree

5 files changed

+94
-7
lines changed

5 files changed

+94
-7
lines changed

src/main/java/dev/openfeature/sdk/EventProvider.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package dev.openfeature.sdk;
22

3+
import dev.openfeature.sdk.internal.ConfigurableThreadFactory;
34
import dev.openfeature.sdk.internal.TriConsumer;
45
import java.util.concurrent.ExecutorService;
56
import java.util.concurrent.Executors;
@@ -21,7 +22,8 @@
2122
@Slf4j
2223
public abstract class EventProvider implements FeatureProvider {
2324
private EventProviderListener eventProviderListener;
24-
private final ExecutorService emitterExecutor = Executors.newCachedThreadPool();
25+
private final ExecutorService emitterExecutor =
26+
Executors.newCachedThreadPool(new ConfigurableThreadFactory("openfeature-event-emitter-thread"));
2527

2628
void setEventProviderListener(EventProviderListener eventProviderListener) {
2729
this.eventProviderListener = eventProviderListener;

src/main/java/dev/openfeature/sdk/EventSupport.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package dev.openfeature.sdk;
22

3+
import dev.openfeature.sdk.internal.ConfigurableThreadFactory;
34
import java.util.Collection;
45
import java.util.Map;
56
import java.util.Optional;
@@ -26,7 +27,8 @@ class EventSupport {
2627
private static final String DEFAULT_CLIENT_UUID = UUID.randomUUID().toString();
2728
private final Map<String, HandlerStore> handlerStores = new ConcurrentHashMap<>();
2829
private final HandlerStore globalHandlerStore = new HandlerStore();
29-
private final ExecutorService taskExecutor = Executors.newCachedThreadPool();
30+
private final ExecutorService taskExecutor =
31+
Executors.newCachedThreadPool(new ConfigurableThreadFactory("openfeature-event-handler-thread"));
3032

3133
/**
3234
* Run all the event handlers associated with this domain.

src/main/java/dev/openfeature/sdk/ProviderRepository.java

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import dev.openfeature.sdk.exceptions.GeneralError;
44
import dev.openfeature.sdk.exceptions.OpenFeatureError;
5+
import dev.openfeature.sdk.internal.ConfigurableThreadFactory;
56
import java.util.List;
67
import java.util.Map;
78
import java.util.Optional;
@@ -22,11 +23,8 @@ class ProviderRepository {
2223
private final Map<String, FeatureProviderStateManager> stateManagers = new ConcurrentHashMap<>();
2324
private final AtomicReference<FeatureProviderStateManager> defaultStateManger =
2425
new AtomicReference<>(new FeatureProviderStateManager(new NoOpProvider()));
25-
private final ExecutorService taskExecutor = Executors.newCachedThreadPool(runnable -> {
26-
final Thread thread = new Thread(runnable);
27-
thread.setDaemon(true);
28-
return thread;
29-
});
26+
private final ExecutorService taskExecutor =
27+
Executors.newCachedThreadPool(new ConfigurableThreadFactory("openfeature-provider-thread", true));
3028
private final Object registerStateManagerLock = new Object();
3129
private final OpenFeatureAPI openFeatureAPI;
3230

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
package dev.openfeature.sdk.internal;
2+
3+
import java.util.concurrent.ThreadFactory;
4+
import java.util.concurrent.atomic.AtomicInteger;
5+
6+
/**
7+
* A configurable thread factory for internal use in the SDK.
8+
* Allows daemon or non-daemon threads to be created with a custom name prefix.
9+
*/
10+
public final class ConfigurableThreadFactory implements ThreadFactory {
11+
12+
private final AtomicInteger counter = new AtomicInteger();
13+
private final String namePrefix;
14+
private final boolean daemon;
15+
16+
/**
17+
* {@link ConfigurableThreadFactory}'s constructor.
18+
*
19+
* @param namePrefix Prefix used for setting the new thread's name.
20+
*/
21+
public ConfigurableThreadFactory(String namePrefix) {
22+
this(namePrefix, false);
23+
}
24+
25+
/**
26+
* {@link ConfigurableThreadFactory}'s constructor.
27+
*
28+
* @param namePrefix Prefix used for setting the new thread's name.
29+
* @param daemon Whether daemon or non-daemon threads will be created.
30+
*/
31+
public ConfigurableThreadFactory(String namePrefix, boolean daemon) {
32+
this.namePrefix = namePrefix;
33+
this.daemon = daemon;
34+
}
35+
36+
@Override
37+
public Thread newThread(Runnable runnable) {
38+
final Thread thread = new Thread(runnable);
39+
thread.setDaemon(daemon);
40+
thread.setName(namePrefix + "-" + counter.incrementAndGet());
41+
return thread;
42+
}
43+
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
package dev.openfeature.sdk.internal;
2+
3+
import static org.assertj.core.api.Assertions.assertThat;
4+
5+
import org.junit.jupiter.api.Test;
6+
7+
class ConfigurableThreadFactoryTest {
8+
9+
private static final String THREAD_NAME = "testthread";
10+
private final Runnable runnable = () -> {};
11+
12+
@Test
13+
void verifyNewThreadHasNamePrefix() {
14+
15+
var configurableThreadFactory = new ConfigurableThreadFactory(THREAD_NAME);
16+
var thread = configurableThreadFactory.newThread(runnable);
17+
18+
assertThat(thread.getName()).isEqualTo(THREAD_NAME + "-1");
19+
assertThat(thread.isDaemon()).isFalse();
20+
}
21+
22+
@Test
23+
void verifyNewThreadHasNamePrefixWithIncrement() {
24+
25+
var configurableThreadFactory = new ConfigurableThreadFactory(THREAD_NAME);
26+
var threadOne = configurableThreadFactory.newThread(runnable);
27+
var threadTwo = configurableThreadFactory.newThread(runnable);
28+
29+
assertThat(threadOne.getName()).isEqualTo(THREAD_NAME + "-1");
30+
assertThat(threadTwo.getName()).isEqualTo(THREAD_NAME + "-2");
31+
}
32+
33+
@Test
34+
void verifyNewDaemonThreadHasNamePrefix() {
35+
36+
var configurableThreadFactory = new ConfigurableThreadFactory(THREAD_NAME, true);
37+
var thread = configurableThreadFactory.newThread(runnable);
38+
39+
assertThat(thread.getName()).isEqualTo(THREAD_NAME + "-1");
40+
assertThat(thread.isDaemon()).isTrue();
41+
}
42+
}

0 commit comments

Comments
 (0)