diff --git a/server/src/main/java/org/elasticsearch/action/support/SubscribableListener.java b/server/src/main/java/org/elasticsearch/action/support/SubscribableListener.java index f0ff1d3b93268..a091cc55ea6c0 100644 --- a/server/src/main/java/org/elasticsearch/action/support/SubscribableListener.java +++ b/server/src/main/java/org/elasticsearch/action/support/SubscribableListener.java @@ -190,13 +190,20 @@ public final void addListener(ActionListener listener) { * then it will be completed using the given executor. If the subscribing listener is completed immediately then * this completion happens on the subscribing thread. *

- * In other words, if you want to ensure that {@code listener} is completed using a particular executor, then you - * must do both of: + * This behaviour may seem complex at first sight, but it is like this to allow callers to ensure that + * {@code listener} is completed using a particular executor much more cheaply than simply always forking the + * completion task to the desired executor. To ensure that {@code listener} is completed using a particular + * executor, do both of the following: *

*

+ * If you really want to fork the completion task to a specific executor in all circumstances, wrap the supplied + * {@code listener} in a {@link ThreadedActionListener} yourself. But do note that this can be surprisingly + * expensive, and it's almost always not the right approach, so it is deliberate that there is no convenient method + * on {@link SubscribableListener} which does this for you. + *

* If {@code executor} rejects the execution of the completion of the subscribing listener then the result is * discarded and the subscribing listener is completed with a rejection exception on the thread which completes * this listener. @@ -480,13 +487,19 @@ public SubscribableListener andThen(CheckedBiConsumer, * The threading of the {@code nextStep} callback is the same as for listeners added with {@link #addListener}: if this listener is * already complete then {@code nextStep} is invoked on the thread calling {@link #andThen} and in its thread context, but if this * listener is incomplete then {@code nextStep} is invoked using {@code executor}, in a thread context captured when {@link #andThen} - * was called. In other words, if you want to ensure that {@code nextStep} is invoked using a particular executor, then you must do - * both of: + * was called. This behaviour may seem complex at first sight but it is like this to allow callers to ensure that {@code nextStep} runs + * using a particular executor much more cheaply than simply always forking its execution. To ensure that {@code nextStep} is invoked + * using a particular executor, do both of the following: *

*

+ * If you really want to fork the execution of the next step in the sequence to a specific executor in all circumstances, explicitly + * call {@link Executor#execute} within {@code nextStep} yourself. But do note that this can be surprisingly expensive, and it's almost + * always not the right approach, so it is deliberate that there is no convenient method on {@link SubscribableListener} which does this + * for you. + *

* If {@code executor} rejects the execution of {@code nextStep} then the result is discarded and the returned listener is completed * with a rejection exception on the thread which completes this listener. Likewise if this listener is completed exceptionally but * {@code executor} rejects the execution of the completion of the returned listener then the returned listener is completed with a