Skip to content

Commit fe4c7b0

Browse files
committed
Propagate async call future cancellation to FailsafeCall
1 parent 4c0b1a2 commit fe4c7b0

File tree

4 files changed

+44
-2
lines changed

4 files changed

+44
-2
lines changed

modules/okhttp/src/main/java/dev/failsafe/okhttp/FailsafeCall.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,10 @@ private okhttp3.Call prepareCall(ExecutionContext<Response> ctx) {
164164
}
165165

166166
// Propagate cancellation to the call
167-
ctx.onCancel(call::cancel);
167+
ctx.onCancel(() -> {
168+
cancelled.set(true);
169+
call.cancel();
170+
});
168171
return call;
169172
}
170173
}

modules/okhttp/src/test/java/dev/failsafe/okhttp/FailsafeCallTest.java

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
import java.io.IOException;
2828
import java.time.Duration;
2929
import java.util.concurrent.CancellationException;
30+
import java.util.concurrent.Future;
3031

3132
import static com.github.tomakehurst.wiremock.client.WireMock.*;
3233
import static org.testng.Assert.assertEquals;
@@ -189,6 +190,23 @@ public void testCancel() {
189190
assertCalled("/test", 2);
190191
}
191192

193+
public void testCancelViaFuture() {
194+
// Given
195+
mockDelayedResponse(200, "foo", 1000);
196+
FailsafeExecutor<Response> failsafe = Failsafe.none();
197+
Call call = callFor("/test");
198+
199+
// When / Then Async
200+
FailsafeCall failsafeCall = FailsafeCall.of(call, failsafe);
201+
Future<Response> future = failsafeCall.executeAsync();
202+
sleep(150);
203+
future.cancel(false);
204+
assertThrows(future::get, CancellationException.class);
205+
assertTrue(call.isCanceled());
206+
assertTrue(failsafeCall.isCancelled());
207+
assertCalled("/test", 1);
208+
}
209+
192210
private Call callFor(String path) {
193211
return client.newCall(new Request.Builder().url(URL + path).build());
194212
}

modules/retrofit/src/main/java/dev/failsafe/retrofit/FailsafeCall.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,10 @@ private retrofit2.Call<T> prepareCall(ExecutionContext<Response<T>> ctx) {
156156
retrofit2.Call<T> call = ctx.isFirstAttempt() ? initialCall : initialCall.clone();
157157

158158
// Propagate cancellation to the call
159-
ctx.onCancel(call::cancel);
159+
ctx.onCancel(() -> {
160+
cancelled.set(true);
161+
call.cancel();
162+
});
160163
return call;
161164
}
162165
}

modules/retrofit/src/test/java/dev/retrofit/FailsafeCallTest.java

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
import java.io.IOException;
3434
import java.time.Duration;
3535
import java.util.concurrent.CancellationException;
36+
import java.util.concurrent.Future;
3637

3738
import static com.github.tomakehurst.wiremock.client.WireMock.*;
3839
import static org.testng.Assert.assertEquals;
@@ -204,6 +205,23 @@ public void testCancel() {
204205
assertCalled("/test", 2);
205206
}
206207

208+
public void testCancelViaFuture() {
209+
// Given
210+
mockDelayedResponse(200, "foo", 1000);
211+
FailsafeExecutor<Response<User>> failsafe = Failsafe.none();
212+
Call<User> call = service.testUser();
213+
FailsafeCall<User> failsafeCall = FailsafeCall.of(call, failsafe);
214+
215+
// When / Then Async
216+
Future<Response<User>> future = failsafeCall.executeAsync();
217+
sleep(150);
218+
future.cancel(false);
219+
assertThrows(future::get, CancellationException.class);
220+
assertTrue(call.isCanceled());
221+
assertTrue(failsafeCall.isCancelled());
222+
assertCalled("/test", 1);
223+
}
224+
207225
private void mockResponse(int responseCode, User body) {
208226
stubFor(get(urlPathEqualTo("/test")).willReturn(
209227
aResponse().withStatus(responseCode).withHeader("Content-Type", "application/json").withBody(gson.toJson(body))));

0 commit comments

Comments
 (0)