Skip to content

Commit aeb430a

Browse files
committed
fix: fix SSEStream unpredictably throws unwanted IOException("Canceled")
1 parent bb11ceb commit aeb430a

File tree

1 file changed

+22
-4
lines changed

1 file changed

+22
-4
lines changed

src/main/java/org/stellar/sdk/requests/SSEStream.java

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ public class SSEStream<T extends org.stellar.sdk.responses.Response> implements
4545
private EventSource eventSource = null;
4646
private final Lock lock = new ReentrantLock();
4747
private final long reconnectTimeout;
48+
private final AtomicLong currentListenerId = new AtomicLong(0);
4849

4950
private SSEStream(
5051
final OkHttpClient okHttpClient,
@@ -83,6 +84,7 @@ public void run() {
8384
}
8485

8586
try {
87+
// TODO: use Executors.newSingleThreadScheduledExecutor() instead
8688
Thread.sleep(200);
8789
if (serverSideClosed.get() || clientSideClosed.get()) {
8890
// don't restart until true again
@@ -116,6 +118,7 @@ private void restart() {
116118
if (eventSource != null) {
117119
eventSource.cancel();
118120
}
121+
long newListenerId = currentListenerId.incrementAndGet();
119122
eventSource =
120123
doStreamRequest(
121124
this,
@@ -129,11 +132,13 @@ private void restart() {
129132
public void closed(EventSource source) {
130133
serverSideClosed.set(true);
131134
}
132-
});
135+
},
136+
newListenerId);
133137
}
134138

135139
public void close() {
136140
isStopped.set(true);
141+
currentListenerId.incrementAndGet(); // Prevent any future EventSource
137142
if (eventSource != null) {
138143
eventSource.cancel();
139144
}
@@ -168,7 +173,8 @@ private static <T extends org.stellar.sdk.responses.Response> EventSource doStre
168173
final Class<T> responseClass,
169174
final EventListener<T> listener,
170175
String url,
171-
final CloseListener closeListener) {
176+
final CloseListener closeListener,
177+
long listenerId) {
172178

173179
Request.Builder builder =
174180
new Request.Builder()
@@ -183,7 +189,7 @@ private static <T extends org.stellar.sdk.responses.Response> EventSource doStre
183189
new RealEventSource(
184190
request,
185191
new StellarEventSourceListener<T>(
186-
stream, closeListener, responseClass, requestBuilder, listener));
192+
stream, closeListener, responseClass, requestBuilder, listener, listenerId));
187193
eventSource.connect(okHttpClient);
188194
return eventSource;
189195
}
@@ -200,22 +206,28 @@ private static class StellarEventSourceListener<T extends org.stellar.sdk.respon
200206
private final Class<T> responseClass;
201207
private final RequestBuilder requestBuilder;
202208
private final EventListener<T> listener;
209+
private final long listenerId;
203210

204211
StellarEventSourceListener(
205212
SSEStream<T> stream,
206213
CloseListener closeListener,
207214
Class<T> responseClass,
208215
RequestBuilder requestBuilder,
209-
EventListener<T> listener) {
216+
EventListener<T> listener,
217+
long listenerId) {
210218
this.stream = stream;
211219
this.closeListener = closeListener;
212220
this.responseClass = responseClass;
213221
this.requestBuilder = requestBuilder;
214222
this.listener = listener;
223+
this.listenerId = listenerId;
215224
}
216225

217226
@Override
218227
public void onClosed(EventSource eventSource) {
228+
if (listenerId != stream.currentListenerId.get()) {
229+
return;
230+
}
219231
if (closeListener != null) {
220232
closeListener.closed(eventSource);
221233
}
@@ -227,6 +239,9 @@ public void onOpen(EventSource eventSource, Response response) {}
227239
@Override
228240
public void onFailure(
229241
EventSource eventSource, @Nullable Throwable t, @Nullable Response response) {
242+
if (listenerId != stream.currentListenerId.get()) {
243+
return;
244+
}
230245
Optional<Integer> code = Optional.empty();
231246
if (response != null) {
232247
code = Optional.of(response.code());
@@ -248,6 +263,9 @@ public void onFailure(
248263
@Override
249264
public void onEvent(
250265
EventSource eventSource, @Nullable String id, @Nullable String type, String data) {
266+
if (listenerId != stream.currentListenerId.get()) {
267+
return;
268+
}
251269
// Update the timestamp of the last received event.
252270
stream.latestEventTime.set(System.currentTimeMillis());
253271

0 commit comments

Comments
 (0)