Skip to content

Commit 20e30c9

Browse files
authored
Add note about response lifecycles in SubscribableListener (#137516)
It's not obvious from these docs that you have to do extra work if the responses in the chain have nontrivial lifecycles. This commit adds some docs to call this out.
1 parent b5a2f43 commit 20e30c9

File tree

1 file changed

+17
-0
lines changed

1 file changed

+17
-0
lines changed

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

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,23 @@
9999
* .addListener(finalListener);
100100
* }
101101
* }</pre>
102+
* <p>
103+
* You must take care when using a chain of {@link SubscribableListener}s where one or more of the response objects have nontrivial
104+
* lifecycles (e.g. they implement {@link org.elasticsearch.core.Releasable} or {@link org.elasticsearch.core.RefCounted}). For example:
105+
* <ul>
106+
* <li>{@link SubscribableListener} silently discards all but one response, whether exceptional or otherwise. The caller must take steps
107+
* to release any discarded responses that need releasing.</li>
108+
* <li>When a {@link SubscribableListener} is completed it keeps hold of the response in case another listener subscribes to this
109+
* response in future (e.g. via {@link #addListener} or {@link #andThen}) but it does not formally take ownership of the response (e.g.
110+
* by calling {@link org.elasticsearch.core.RefCounted#incRef}). In particular, in the usual pattern ...
111+
* <pre>{@code
112+
* SubscribableListener.newForked(l1 -> step1(l1)).andThen((l2, r1) -> step2(r1, l2))...
113+
* }</pre>
114+
* ... if {@code r1} is ref-counted then usually {@code step1} will call {@link org.elasticsearch.core.RefCounted#decRef} immediately
115+
* after {@code l1.onResponse(r1)} returns since it no longer needs to keep the response alive itself. This is a problem because it may
116+
* happen before the {@link #andThen} adds the second step to the chain, so that by the time {@code step2} runs the response {@code r1}
117+
* may already be fully-released. The caller must take steps to keep responses alive until they are no longer needed.</li>
118+
* </ul>
102119
*/
103120
public class SubscribableListener<T> implements ActionListener<T> {
104121

0 commit comments

Comments
 (0)