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

Allow client cancel grpc unary request incase client streaming data #12023

Closed
1 task done
tanhv90 opened this issue Jul 13, 2023 · 1 comment
Closed
1 task done

Allow client cancel grpc unary request incase client streaming data #12023

tanhv90 opened this issue Jul 13, 2023 · 1 comment
Labels
needs triage This issue has not been looked into type: enhancement 🐺

Comments

@tanhv90
Copy link
Contributor

tanhv90 commented Jul 13, 2023

Is there an existing issue that is already proposing this?

  • I have searched the existing issues

Is your feature request related to a problem? Please describe it

When unsubscribe from grpc client call unary method with client streaming data, it does nothing, so:

  • grpc call be hang
  • cannot cancel grpc call

Describe the solution you'd like

  • Call grpc call.cancel() if(!call.finished)

Teachability, documentation, adoption, migration strategy

public createUnaryServiceMethod(
    client: any,
    methodName: string,
  ): (...args: any[]) => Observable<any> {
    return (...args: any[]) => {
      const isRequestStream = client[methodName].requestStream;
      const upstreamSubjectOrData = args[0];
      const isUpstreamSubject =
        upstreamSubjectOrData && isFunction(upstreamSubjectOrData.subscribe);

      if (isRequestStream && isUpstreamSubject) {
        return new Observable(observer => {
          let isClientCanceled = false;
          const callArgs = [
            (error: any, data: unknown) => {
              if (error) {
                if (error.details === GRPC_CANCELLED) {
                  call.destroy();
                  if (isClientCanceled) {
                    return;
                  }
                }
              return observer.error(this.serializeError(error));
              }
              observer.next(data);
              observer.complete();
            },
          ];
          const maybeMetadata = args[1];
          if (maybeMetadata) {
            callArgs.unshift(maybeMetadata);
          }
          const call = client[methodName](...callArgs);

          const upstreamSubscription: Subscription =
            upstreamSubjectOrData.subscribe(
              (val: unknown) => call.write(val),
              (err: unknown) => call.emit('error', err),
              () => call.end(),
            );

          return () => {
            upstreamSubscription.unsubscribe();
            if (!call.finished) {
              isClientCanceled = true;
              call.cancel();
            }
          };
        });
      }
      return new Observable(observer => {
        const call = client[methodName](...args, (error: any, data: any) => {
          if (error) {
            return observer.error(this.serializeError(error));
          }
          observer.next(data);
          observer.complete();
        });

        return () => {
          if (!call.finished) {
            call.cancel();
          }
        };
      });
    };
  }

The code update may be look like that. I'm trying in my PC and seem it work.

What is the motivation / use case for changing the behavior?

Allow client cancel request

@kamilmysliwiec
Copy link
Member

Let's track this here #12026

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
needs triage This issue has not been looked into type: enhancement 🐺
Projects
None yet
Development

No branches or pull requests

2 participants