@@ -34,17 +34,8 @@ public class ResourceBasedSlotSupplier<SI extends SlotInfo> implements SlotSuppl
3434 private final ResourceBasedSlotOptions options ;
3535 private Instant lastSlotIssuedAt = Instant .EPOCH ;
3636 // For slot reservations that are waiting to re-check resource usage
37- private static final ScheduledExecutorService scheduler =
38- Executors .newScheduledThreadPool (
39- // Two threads seem needed here, so that reading PID decisions doesn't interfere overly
40- // with firing off scheduled tasks or one another.
41- 2 ,
42- r -> {
43- Thread t = new Thread (r );
44- t .setName ("ResourceBasedSlotSupplier.scheduler" );
45- t .setDaemon (true );
46- return t ;
47- });
37+ private final ScheduledExecutorService scheduler ;
38+ private static ScheduledExecutorService defaultScheduler ;
4839
4940 /**
5041 * Construct a slot supplier for workflow tasks with the given resource controller and options.
@@ -55,7 +46,20 @@ public class ResourceBasedSlotSupplier<SI extends SlotInfo> implements SlotSuppl
5546 public static ResourceBasedSlotSupplier <WorkflowSlotInfo > createForWorkflow (
5647 ResourceBasedController resourceBasedController , ResourceBasedSlotOptions options ) {
5748 return new ResourceBasedSlotSupplier <>(
58- WorkflowSlotInfo .class , resourceBasedController , options );
49+ WorkflowSlotInfo .class , resourceBasedController , options , null );
50+ }
51+
52+ /**
53+ * As {@link #createForWorkflow(ResourceBasedController, ResourceBasedSlotOptions)}, but allows
54+ * overriding the internal thread pool. It is recommended to share the same executor across all
55+ * resource based slot suppliers in a worker.
56+ */
57+ public static ResourceBasedSlotSupplier <WorkflowSlotInfo > createForWorkflow (
58+ ResourceBasedController resourceBasedController ,
59+ ResourceBasedSlotOptions options ,
60+ ScheduledExecutorService scheduler ) {
61+ return new ResourceBasedSlotSupplier <>(
62+ WorkflowSlotInfo .class , resourceBasedController , options , scheduler );
5963 }
6064
6165 /**
@@ -67,7 +71,20 @@ public static ResourceBasedSlotSupplier<WorkflowSlotInfo> createForWorkflow(
6771 public static ResourceBasedSlotSupplier <ActivitySlotInfo > createForActivity (
6872 ResourceBasedController resourceBasedController , ResourceBasedSlotOptions options ) {
6973 return new ResourceBasedSlotSupplier <>(
70- ActivitySlotInfo .class , resourceBasedController , options );
74+ ActivitySlotInfo .class , resourceBasedController , options , null );
75+ }
76+
77+ /**
78+ * As {@link #createForActivity(ResourceBasedController, ResourceBasedSlotOptions)}, but allows
79+ * overriding the internal thread pool. It is recommended to share the same executor across all
80+ * resource based slot suppliers in a worker.
81+ */
82+ public static ResourceBasedSlotSupplier <ActivitySlotInfo > createForActivity (
83+ ResourceBasedController resourceBasedController ,
84+ ResourceBasedSlotOptions options ,
85+ ScheduledExecutorService scheduler ) {
86+ return new ResourceBasedSlotSupplier <>(
87+ ActivitySlotInfo .class , resourceBasedController , options , scheduler );
7188 }
7289
7390 /**
@@ -79,7 +96,20 @@ public static ResourceBasedSlotSupplier<ActivitySlotInfo> createForActivity(
7996 public static ResourceBasedSlotSupplier <LocalActivitySlotInfo > createForLocalActivity (
8097 ResourceBasedController resourceBasedController , ResourceBasedSlotOptions options ) {
8198 return new ResourceBasedSlotSupplier <>(
82- LocalActivitySlotInfo .class , resourceBasedController , options );
99+ LocalActivitySlotInfo .class , resourceBasedController , options , null );
100+ }
101+
102+ /**
103+ * As {@link #createForLocalActivity(ResourceBasedController, ResourceBasedSlotOptions)}, but
104+ * allows overriding the internal thread pool. It is recommended to share the same executor across
105+ * all resource based slot suppliers in a worker.
106+ */
107+ public static ResourceBasedSlotSupplier <LocalActivitySlotInfo > createForLocalActivity (
108+ ResourceBasedController resourceBasedController ,
109+ ResourceBasedSlotOptions options ,
110+ ScheduledExecutorService scheduler ) {
111+ return new ResourceBasedSlotSupplier <>(
112+ LocalActivitySlotInfo .class , resourceBasedController , options , scheduler );
83113 }
84114
85115 /**
@@ -90,14 +120,34 @@ public static ResourceBasedSlotSupplier<LocalActivitySlotInfo> createForLocalAct
90120 */
91121 public static ResourceBasedSlotSupplier <NexusSlotInfo > createForNexus (
92122 ResourceBasedController resourceBasedController , ResourceBasedSlotOptions options ) {
93- return new ResourceBasedSlotSupplier <>(NexusSlotInfo .class , resourceBasedController , options );
123+ return new ResourceBasedSlotSupplier <>(
124+ NexusSlotInfo .class , resourceBasedController , options , null );
125+ }
126+
127+ /**
128+ * As {@link #createForNexus(ResourceBasedController, ResourceBasedSlotOptions)}, but allows
129+ * overriding the internal thread pool. It is recommended to share the same executor across all
130+ * resource based slot suppliers in a worker.
131+ */
132+ public static ResourceBasedSlotSupplier <NexusSlotInfo > createForNexus (
133+ ResourceBasedController resourceBasedController ,
134+ ResourceBasedSlotOptions options ,
135+ ScheduledExecutorService scheduler ) {
136+ return new ResourceBasedSlotSupplier <>(
137+ NexusSlotInfo .class , resourceBasedController , options , scheduler );
94138 }
95139
96140 private ResourceBasedSlotSupplier (
97141 Class <SI > clazz ,
98142 ResourceBasedController resourceBasedController ,
99- ResourceBasedSlotOptions options ) {
143+ ResourceBasedSlotOptions options ,
144+ ScheduledExecutorService scheduler ) {
100145 this .resourceController = resourceBasedController ;
146+ if (scheduler == null ) {
147+ this .scheduler = getDefaultScheduler ();
148+ } else {
149+ this .scheduler = scheduler ;
150+ }
101151 // Merge default options for any unset fields
102152 if (WorkflowSlotInfo .class .isAssignableFrom (clazz )) {
103153 this .options =
@@ -152,7 +202,7 @@ private ResourceBasedSlotSupplier(
152202 }
153203
154204 @ Override
155- public CompletableFuture <SlotPermit > reserveSlot (SlotReserveContext <SI > ctx ) {
205+ public CompletableFuture <SlotPermit > reserveSlot (SlotReserveContext <SI > ctx ) throws Exception {
156206 if (ctx .getNumIssuedSlots () < options .getMinimumSlots ()) {
157207 return CompletableFuture .completedFuture (new SlotPermit ());
158208 }
@@ -219,7 +269,26 @@ private Duration timeSinceLastSlotIssued() {
219269 }
220270
221271 // Polyfill for Java 9 delayedExecutor
222- private static Executor delayedExecutor (long delay ) {
272+ private Executor delayedExecutor (long delay ) {
223273 return r -> scheduler .schedule (() -> scheduler .execute (r ), delay , TimeUnit .MILLISECONDS );
224274 }
275+
276+ private static ScheduledExecutorService getDefaultScheduler () {
277+ synchronized (ResourceBasedSlotSupplier .class ) {
278+ if (defaultScheduler == null ) {
279+ defaultScheduler =
280+ Executors .newScheduledThreadPool (
281+ // Two threads seem needed here, so that reading PID decisions doesn't interfere
282+ // overly with firing off scheduled tasks or one another.
283+ 2 ,
284+ r -> {
285+ Thread t = new Thread (r );
286+ t .setName ("ResourceBasedSlotSupplier.scheduler" );
287+ t .setDaemon (true );
288+ return t ;
289+ });
290+ }
291+ return defaultScheduler ;
292+ }
293+ }
225294}
0 commit comments