Skip to content

Commit 8dbff5b

Browse files
committed
core: DelayedClientCall should propagate context
This was already being done for the Listener, but it was missed for the ClientCall draining itself. That's not too surprising, since very few things should be looking at the context in that path. We don't care too much about this client call case, but if the context _does_ end up mattering it could be painful to debug. Fixes grpc#9478
1 parent b778947 commit 8dbff5b

File tree

2 files changed

+34
-2
lines changed

2 files changed

+34
-2
lines changed

core/src/main/java/io/grpc/internal/DelayedClientCall.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -152,9 +152,9 @@ public final Runnable setCall(ClientCall<ReqT, RespT> call) {
152152
}
153153
setRealCall(checkNotNull(call, "call"));
154154
}
155-
return new Runnable() {
155+
return new ContextRunnable(context) {
156156
@Override
157-
public void run() {
157+
public void runInContext() {
158158
drainPendingCalls();
159159
}
160160
};

core/src/test/java/io/grpc/internal/DelayedClientCallTest.java

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,9 @@
2727
import com.google.common.util.concurrent.MoreExecutors;
2828
import io.grpc.ClientCall;
2929
import io.grpc.ClientCall.Listener;
30+
import io.grpc.Context;
3031
import io.grpc.Deadline;
32+
import io.grpc.ForwardingClientCall.SimpleForwardingClientCall;
3133
import io.grpc.ForwardingTestUtil;
3234
import io.grpc.Metadata;
3335
import io.grpc.Status;
@@ -36,6 +38,7 @@
3638
import java.lang.reflect.Modifier;
3739
import java.util.Arrays;
3840
import java.util.concurrent.Executor;
41+
import java.util.concurrent.atomic.AtomicReference;
3942
import org.junit.Rule;
4043
import org.junit.Test;
4144
import org.junit.runner.RunWith;
@@ -191,6 +194,35 @@ public void setCallThenCancel() {
191194
verify(listener).onClose(Status.CANCELLED, null);
192195
}
193196

197+
@Test
198+
public void delayedCallsRunUnderContext() throws Exception {
199+
Context.Key<Object> contextKey = Context.key("foo");
200+
Object goldenValue = new Object();
201+
DelayedClientCall<String, Integer> delayedClientCall =
202+
Context.current().withValue(contextKey, goldenValue).call(() ->
203+
new DelayedClientCall<>(callExecutor, fakeClock.getScheduledExecutorService(), null));
204+
AtomicReference<Context> readyContext = new AtomicReference<>();
205+
delayedClientCall.start(new ClientCall.Listener<Integer>() {
206+
@Override public void onReady() {
207+
readyContext.set(Context.current());
208+
}
209+
}, new Metadata());
210+
AtomicReference<Context> startContext = new AtomicReference<>();
211+
Runnable r = delayedClientCall.setCall(new SimpleForwardingClientCall<String, Integer>(
212+
mockRealCall) {
213+
@Override public void start(Listener<Integer> listener, Metadata metadata) {
214+
startContext.set(Context.current());
215+
listener.onReady(); // Delayed until call finishes draining
216+
assertThat(readyContext.get()).isNull();
217+
super.start(listener, metadata);
218+
}
219+
});
220+
assertThat(r).isNotNull();
221+
r.run();
222+
assertThat(contextKey.get(startContext.get())).isEqualTo(goldenValue);
223+
assertThat(contextKey.get(readyContext.get())).isEqualTo(goldenValue);
224+
}
225+
194226
private void callMeMaybe(Runnable r) {
195227
if (r != null) {
196228
r.run();

0 commit comments

Comments
 (0)