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

Let GrpcService specify a maximum bound for grpc-timeout #5709

Open
jrhee17 opened this issue May 31, 2024 · 6 comments
Open

Let GrpcService specify a maximum bound for grpc-timeout #5709

jrhee17 opened this issue May 31, 2024 · 6 comments
Milestone

Comments

@jrhee17
Copy link
Contributor

jrhee17 commented May 31, 2024

Currently, armeria has a useClientTimeoutHeader option to decide whether to respect the grpc-timeout request header or not.

Since useClientTimeoutHeader = true delegates the timeout value to the client-side, it is potentially dangerous.
On the other hand, setting useClientTimeoutHeader = false completely ignores the client header and Armeria's requestTimeout is used.

We may want to offer users a middle ground: Armeria server tries to respect the grpc-timeout header, but clamps the timeout according to a bound.

In order to support this, we may deprecate the previous useClientTimeoutHeader and accept a function which determines how to decide the request timeout. This might also be useful if users want to set timeouts depending on the remote.

@Deprecated
GrpcServiceBuilder useClientTimeoutHeader(boolean useClientTimeoutHeader) {}

interface GrpcRequestTimeoutMapper {

  long map(RequestHeaders headers, ServiceRequestContext ctx);

  static GrpcRequestTimeoutMapper USE_CLIENT_TIMEOUT_HEADER = (headers, ctx) -> {
    // https://github.com/line/armeria/blob/e263d76deff8f936a58db69de6ad63d0c0458407/grpc/src/main/java/com/linecorp/armeria/server/grpc/FramedGrpcService.java#L226-L254    
  }

  static GrpcRequestTimeoutMapper USE_SERVER_REQUEST_TIMEOUT = (ignored, ctx) -> TimeUnit.MILLISECONDS.toNanos(ctx.requestTimeoutMillis());
}

GrpcServiceBuilder requestTimeout(GrpcRequestTimeoutMapper mapper) {}
...
GrpcRequestTimeoutMapper mapper;
...
HttpResponse doPost {
  // returns nanos
  long timeout = mapper.map(headers, ctx);
  if (timeout <= 0) {
    ctx.clearRequestTimeout();
  } else {
    ctx.setRequestTimeout(TimeoutMode.SET_FROM_NOW, Duration.ofNanos(timeout));
  }
}
...

ref: https://discord.com/channels/1087271586832318494/1245876539682324642/1245948161835667528

@jrhee17 jrhee17 added this to the 1.30.0 milestone May 31, 2024
@ikhoon
Copy link
Contributor

ikhoon commented May 31, 2024

grpc-timeout is not just a number. A suffix representing a time unit such as s, m or n is appended to the value. It would be a hassle to parse the value.

How about passing the parsed grpc-timeout value to the interface?

interface GrpcClientTimeoutHandler {
    static GrpcClientTimeoutHandler enabled() {
       return Function.identity();
    }
    
    static GrpcClientTimeoutHandler disabled() {
       return (ctx, timeout) -> -1;
    }

    static GrpcClientTimeoutHandler withBuffer(long bufferMillis) {
       return (ctx, timeout) -> timeout + buffer;
    }

    long apply(ServiceRequestContext ctx, long timeoutMillis);
}

@jrhee17
Copy link
Contributor Author

jrhee17 commented May 31, 2024

How about passing the parsed grpc-timeout value to the interface?

The original intention was that users may want to know other header values when clamping the timeout.
However, I realized that this information is in ctx.request().headers() anyways, so the interface you suggested seems better. (The only concern I have is nanos vs. millis)

@jrhee17
Copy link
Contributor Author

jrhee17 commented May 31, 2024

Also possibly related #3155

@ikhoon
Copy link
Contributor

ikhoon commented May 31, 2024

er. (The only concern I have is nanos vs. millis

If it is considerable, Duration may be an alternative.

@Dogacel
Copy link
Contributor

Dogacel commented Jun 1, 2024

I wonder if any of the server side flags affect the timeout behavior?

  • defaultRequestTimeoutMillis
  • defaultResponseTimeoutMillis

etc. IIRC some of those caused connection to be terminated pre-maturely before client initiates a timeout.

@ikhoon
Copy link
Contributor

ikhoon commented Jun 1, 2024

Timeout does not cause connections to be terminated. In HTTP/2, the timeout sends an error response and the connection will be reused.

I wonder if any of the server side flags affect the timeout behavior?

Possible. We are going to provide an option to allow grpc-timeout but the maximum value is limited by defaultRequestTimeoutMillis.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants