Skip to content

Commit 2f66868

Browse files
authored
Expand docs about executor param in SubscribableListener (#127746) (#127870)
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 96a6965 commit 2f66868

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.
@@ -480,13 +487,19 @@ public <U> SubscribableListener<U> andThen(CheckedBiConsumer<ActionListener<U>,
480487
* The threading of the {@code nextStep} callback is the same as for listeners added with {@link #addListener}: if this listener is
481488
* already complete then {@code nextStep} is invoked on the thread calling {@link #andThen} and in its thread context, but if this
482489
* listener is incomplete then {@code nextStep} is invoked using {@code executor}, in a thread context captured when {@link #andThen}
483-
* was called. In other words, if you want to ensure that {@code nextStep} is invoked using a particular executor, then you must do
484-
* both of:
490+
* was called. This behaviour may seem complex at first sight but it is like this to allow callers to ensure that {@code nextStep} runs
491+
* using a particular executor much more cheaply than simply always forking its execution. To ensure that {@code nextStep} is invoked
492+
* using a particular executor, do both of the following:
485493
* <ul>
486494
* <li>Pass the desired executor in as {@code executor}, and</li>
487495
* <li>Invoke {@link #andThen} using that executor.</li>
488496
* </ul>
489497
* <p>
498+
* If you really want to fork the execution of the next step in the sequence to a specific executor in all circumstances, explicitly
499+
* call {@link Executor#execute} within {@code nextStep} yourself. But do note that this can be surprisingly expensive, and it's almost
500+
* always not the right approach, so it is deliberate that there is no convenient method on {@link SubscribableListener} which does this
501+
* for you.
502+
* <p>
490503
* If {@code executor} rejects the execution of {@code nextStep} then the result is discarded and the returned listener is completed
491504
* with a rejection exception on the thread which completes this listener. Likewise if this listener is completed exceptionally but
492505
* {@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)