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

Managed gRPC client #212

Merged
merged 13 commits into from
May 2, 2019
Merged

Managed gRPC client #212

merged 13 commits into from
May 2, 2019

Conversation

JamesNK
Copy link
Member

@JamesNK JamesNK commented Apr 16, 2019

Addresses #43

To do:

  • Validating content type
  • Deadline (client timeout)
  • Deadline (copying C-core HTTP request header formatting)
  • CallOptions.CancellationToken

Future:

  • Compression
  • CallOptions.WriteOptions
  • CallOptions.PropagationToken
  • CallOptions.Credentials
  • CallOptions.IsWaitForReady

@JamesNK JamesNK marked this pull request as ready for review April 16, 2019 10:28
Copy link
Contributor

@JunTaoLuo JunTaoLuo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Initial comments. Still reviewing.


namespace Grpc.NetCore.HttpClient.Internal
{
internal static class GrpcProtocolConstants
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need a better way to share these constants between the projects.


namespace Grpc.NetCore.HttpClient.Internal
{
internal static class GrpcProtocolHelpers
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here.

Copy link

@rynowak rynowak Apr 30, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The world is a better place when you just drop the word "helpers" from these apis. 😆

JunTaoLuo
JunTaoLuo previously approved these changes Apr 17, 2019
Copy link
Contributor

@JunTaoLuo JunTaoLuo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good overall.

Copy link
Contributor

@jtattermusch jtattermusch left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is mostly looking good, but I'd still like to give it a closer look next week. If this PR is blocking your other work though, feel free to merge after addressing comments.

@JamesNK JamesNK force-pushed the jamesnk/grpc-client-wip branch from cbdfac4 to 547a77c Compare April 26, 2019 07:58
@JamesNK
Copy link
Member Author

JamesNK commented Apr 26, 2019

Big update. @jtattermusch Can you review the interop test client? I'd like to merge this and get the HttpClient gRPC client running in your interop environment ASAP. If there are failures caused by other servers, and the problem is HttpClient then we need to get issues raised to the HttpClient team quickly.

Interop test status:

  • "empty_unary"
  • "large_unary"
  • "client_streaming"
  • "server_streaming"
  • "ping_pong" - Fails
  • "empty_stream"
  • "compute_engine_creds" - Fails
  • "jwt_token_creds" - Fails
  • "oauth2_auth_token" - Fails
  • "per_rpc_creds" - Fails
  • "cancel_after_begin"
  • "cancel_after_first_response" - Fails
  • "timeout_on_sleeping_server"
  • "custom_metadata"
  • "status_code_and_message"
  • "unimplemented_service"
  • "unimplemented_method"
  • "client_compressed_unary" - Fails
  • "client_compressed_streaming" - Fails

@@ -1,5 +1,5 @@
{
"sdk": {
"version": "3.0.100-preview4-011108"
"version": "3.0.100-preview6-011568"
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated the SDK so HttpClient supports making HTTP/2 requests without TLS.

if (_timeout != null)
{
// Deadline timer will cancel the call CTS
_deadlineTimer = new Timer(DeadlineExceeded, null, _timeout.Value, Timeout.InfiniteTimeSpan);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's the reason to use this instead of .CancelAfter?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A different status is returned depending on whether the call was cancelled via a token or via the deadline being exceeded. A CTS doesn't provide a reason why it was cancelled (Cancel vs CancelAfter)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It might be better to construct a new CTS with the specified timeout and register DeadlineExceeded with that instead of using a timer. That way when you dispose the registration, you wait for DeadlineExceeded to complete (if it's currently executing) automatically.


public void Dispose()
{
if (!Disposed)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's not super clear to me what the threading model is for this (since you've got cancellation and timeouts). How does this work without locking?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm concerned about this too.

As long as the GrpcCall object itself is accessed from a single logical thread and then disposed after it's used, _ctsRegistration?.Dispose() should block until any possibly-already-triggered calls to CancelCall complete. This effectively locks on our behalf.

I don't know if _deadlineTimer?.Dispose() will similarly wait for DeadlineExceeded to complete. I don't think it does. It would be tempting to use a lock in Dispose and DeadlineExceeded to protect against ODE's, but you risk deadlocking if you're not extremely careful.

After a lot of effort trying to properly dispose the CTS backing the RequestAborted token without ODEs or deadlocking, @jkotalik and I found the best way to avoid deadlocking is to simply not even try disposing CTS that's already been canceled. dotnet/aspnetcore#9333

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think you need to do anything as complicated as what we did for the RequestAborted token since you don't try to lazily allocate the CTS nor do you expose the CancellationToken to the end user.

I do think that using a CTS instead of a Timer for DeadlineExceeded might help you avoid an ODE in DeadlineExceeded though.

Copy link
Member Author

@JamesNK JamesNK Apr 30, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Dispose, cancellation and error handling is immature at the moment.

Dispose can happen 3 ways:

  1. Response headers are invalid (bad HttpStatusCode or bad content type)
  2. Response is received and we finish reading the body
  3. User explicitly calls dispose on the public API, which gets routed here

Then there are additional ways _callCts can be canceled:

  1. The deadline could be exceeded
  2. The user's passed in cancellation token is cancelled

There definitely needs to be some changes here to avoid cancelling an already disposed _callCts.

Copy link
Contributor

@JunTaoLuo JunTaoLuo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Implementation looks good, going to look through the tests before signing off.

return new RpcException(new Status(statusCode, string.Empty));
}

public void FinishResponse()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this threadsafe?

@JamesNK
Copy link
Member Author

JamesNK commented May 2, 2019

Merging so this can be setup in the interop tests.

Still work to do in follow up PRs to get thread-safety perfect but that can be handled in follow up work.

Thanks for everyone's feedback.

@JamesNK JamesNK merged commit 4062ba4 into grpc:master May 2, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants