Skip to content

Commit cc536db

Browse files
authored
Expand docs about executor param in SubscribableListener (#127746)
Provide a little more justification for why we do not always fork to the provided `executor` since it's a little counterintuitive at first sight.
1 parent de1351d commit cc536db

File tree

1 file changed

+17
-4
lines changed

1 file changed

+17
-4
lines changed

server/src/main/java/org/elasticsearch/action/support/SubscribableListener.java

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -190,13 +190,20 @@ public final void addListener(ActionListener<T> listener) {
190190
* then it will be completed using the given executor. If the subscribing listener is completed immediately then
191191
* this completion happens on the subscribing thread.
192192
* <p>
193-
* In other words, if you want to ensure that {@code listener} is completed using a particular executor, then you
194-
* must do both of:
193+
* This behaviour may seem complex at first sight, but it is like this to allow callers to ensure that
194+
* {@code listener} is completed using a particular executor much more cheaply than simply always forking the
195+
* completion task to the desired executor. To ensure that {@code listener} is completed using a particular
196+
* executor, do both of the following:
195197
* <ul>
196198
* <li>Pass the desired executor in as {@code executor}, and</li>
197199
* <li>Invoke {@link #addListener} using that executor.</li>
198200
* </ul>
199201
* <p>
202+
* If you really want to fork the completion task to a specific executor in all circumstances, wrap the supplied
203+
* {@code listener} in a {@link ThreadedActionListener} yourself. But do note that this can be surprisingly
204+
* expensive, and it's almost always not the right approach, so it is deliberate that there is no convenient method
205+
* on {@link SubscribableListener} which does this for you.
206+
* <p>
200207
* If {@code executor} rejects the execution of the completion of the subscribing listener then the result is
201208
* discarded and the subscribing listener is completed with a rejection exception on the thread which completes
202209
* this listener.
@@ -487,13 +494,19 @@ public <U> SubscribableListener<U> andThen(CheckedBiConsumer<ActionListener<U>,
487494
* The threading of the {@code nextStep} callback is the same as for listeners added with {@link #addListener}: if this listener is
488495
* already complete then {@code nextStep} is invoked on the thread calling {@link #andThen} and in its thread context, but if this
489496
* listener is incomplete then {@code nextStep} is invoked using {@code executor}, in a thread context captured when {@link #andThen}
490-
* was called. In other words, if you want to ensure that {@code nextStep} is invoked using a particular executor, then you must do
491-
* both of:
497+
* was called. This behaviour may seem complex at first sight but it is like this to allow callers to ensure that {@code nextStep} runs
498+
* using a particular executor much more cheaply than simply always forking its execution. To ensure that {@code nextStep} is invoked
499+
* using a particular executor, do both of the following:
492500
* <ul>
493501
* <li>Pass the desired executor in as {@code executor}, and</li>
494502
* <li>Invoke {@link #andThen} using that executor.</li>
495503
* </ul>
496504
* <p>
505+
* If you really want to fork the execution of the next step in the sequence to a specific executor in all circumstances, explicitly
506+
* call {@link Executor#execute} within {@code nextStep} yourself. But do note that this can be surprisingly expensive, and it's almost
507+
* always not the right approach, so it is deliberate that there is no convenient method on {@link SubscribableListener} which does this
508+
* for you.
509+
* <p>
497510
* If {@code executor} rejects the execution of {@code nextStep} then the result is discarded and the returned listener is completed
498511
* with a rejection exception on the thread which completes this listener. Likewise if this listener is completed exceptionally but
499512
* {@code executor} rejects the execution of the completion of the returned listener then the returned listener is completed with a

0 commit comments

Comments
 (0)