Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support gRPC cancellation #5570

Open
ikhoon opened this issue Apr 5, 2024 · 3 comments
Open

Support gRPC cancellation #5570

ikhoon opened this issue Apr 5, 2024 · 3 comments
Labels
new feature sprint Issues for OSS Sprint participants

Comments

@ikhoon
Copy link
Contributor

ikhoon commented Apr 5, 2024

Currently, Armeria gRPC implementation does not support cancellation at the gRPC level.
https://github.com/grpc/grpc-java/blob/1d6f1f1b4251191bddb9d6605fc8f8152275b6b7/examples/src/main/java/io/grpc/examples/cancellation/CancellationClient.java#L57

When a call is canceled, the upstream sends RST_FRAME. We can make the same effect by calling RequestContext.cancel().

It sounds easy but the implementation on the client side could be tricky. On the call path, ClientInterceptor is called first, and then ArmeriaChannel is called.
As ClientRequestContext is created in ArmeriaChannel, ClientRequestContext is inaccessible in ClientInterceptor. So our aim to call 'RequestContext.cancel()' is not feasible.

The idea I came up with is to add a ClientInterceptor in the GrpcClientBuilder that gets executed first. The interceptor registers a CancellationListener to CancellationContext. The reference of the registered CancellationListener should be also added to CallOptions so that we can update ClientRequestContext to the reference in ArmeriaChannel.newCall().

static CallOptions.Key<CancellationHandler> KEY = CallOptions.Key.create(CancellationHandler.class.getName());

class CancellableClientInterceptor {
    ...
    @Override
    public <ReqT, RespT> ClientCall<ReqT, RespT> interceptCall(
           MethodDescriptor<ReqT, RespT> method, CallOptions callOptions,
           Channel next) {
       // CancellationHandler will defer the cancellation until `ClientRequestContext` to this.
       final CancellationHandler handler = new CancellationHandler();
       // KEY will be used in ArmeriaChannel.newCall() to get `handler`
       callOptions = callOptions.withOption(KEY, handler);
       final CancellableContext context = Context.current().withCancellation();
       context.addListener(handler, MoreExecutors.directExecutor());
       Context previous = context.attach();
       try {
           return next.newCall(method, callOptions);
       } finally {
           context.detach(previous);
       }
   }
}
@ikhoon ikhoon added new feature sprint Issues for OSS Sprint participants labels Apr 5, 2024
@my4-dev
Copy link
Contributor

my4-dev commented Apr 14, 2024

Hi, @ikhoon ~

I understand that this issue requirement is To call RequestContext.cancel() when gRPC level cancellation occurs.

Thank you for sharing your idea and implementation outline.
I'm not completely sure the following implementation and how this handler can access to ClientRequestContext.

       // CancellationHandler will defer the cancellation until `ClientRequestContext` to this.
       final CancellationHandler handler = new CancellationHandler();

Do you have your idea about this already?
If so, it would be helpful if you could share.

@ikhoon
Copy link
Contributor Author

ikhoon commented Apr 15, 2024

We can set ClientRequestContext to CancellationHandler in the following method.

final DefaultClientRequestContext ctx = newContext(HttpMethod.POST, req, method);

CancellationHandler invokes ClientRequestContext.cancel() when it is set if CancellationListener.cancelled() was called before.

By the way, this issue is labeled with sprint so a sprint member is scheduled to work on this. 😅 How about looking for another issue?

@my4-dev
Copy link
Contributor

my4-dev commented Apr 15, 2024

Oh! Got it.
I'm sorry for misunderstanding of this labeling system.
Thank you for sharing your idea.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
new feature sprint Issues for OSS Sprint participants
Projects
None yet
Development

No branches or pull requests

2 participants