Welcome! Log In Create A New Profile

Advanced

[nginx] gRPC: improved keepalive handling.

Maxim Dounin
December 04, 2018 08:38AM
details: https://hg.nginx.org/nginx/rev/c948804cd628
branches: stable-1.14
changeset: 7416:c948804cd628
user: Maxim Dounin <mdounin@mdounin.ru>
date: Mon Sep 03 19:34:01 2018 +0300
description:
gRPC: improved keepalive handling.

The code is now able to parse additional control frames after
the response is received, and can send control frames as well.
This fixes keepalive problems as observed with grpc-c, which can
send window update and ping frames after the response, see
http://mailman.nginx.org/pipermail/nginx/2018-August/056620.html.

diffstat:

src/http/modules/ngx_http_grpc_module.c | 100 +++++++++++++++++++++----------
1 files changed, 67 insertions(+), 33 deletions(-)

diffs (173 lines):

diff --git a/src/http/modules/ngx_http_grpc_module.c b/src/http/modules/ngx_http_grpc_module.c
--- a/src/http/modules/ngx_http_grpc_module.c
+++ b/src/http/modules/ngx_http_grpc_module.c
@@ -114,6 +114,7 @@ typedef struct {
unsigned output_closed:1;
unsigned parsing_headers:1;
unsigned end_stream:1;
+ unsigned done:1;
unsigned status:1;

ngx_http_request_t *request;
@@ -1077,6 +1078,7 @@ ngx_http_grpc_reinit_request(ngx_http_re
ctx->output_closed = 0;
ctx->parsing_headers = 0;
ctx->end_stream = 0;
+ ctx->done = 0;
ctx->status = 0;
ctx->connection = NULL;

@@ -1096,6 +1098,7 @@ ngx_http_grpc_body_output_filter(void *d
ngx_int_t rc;
ngx_uint_t next, last;
ngx_chain_t *cl, *out, **ll;
+ ngx_http_upstream_t *u;
ngx_http_grpc_ctx_t *ctx;
ngx_http_grpc_frame_t *f;

@@ -1410,6 +1413,28 @@ ngx_http_grpc_body_output_filter(void *d
rc = NGX_AGAIN;
}

+ if (ctx->done) {
+
+ /*
+ * We have already got the response and were sending some additional
+ * control frames. Even if there is still something unsent, stop
+ * here anyway.
+ */
+
+ u = r->upstream;
+ u->length = 0;
+
+ if (ctx->in == NULL
+ && ctx->out == NULL
+ && ctx->output_closed
+ && ctx->state == ngx_http_grpc_st_start)
+ {
+ u->keepalive = 1;
+ }
+
+ ngx_post_event(u->peer.connection->read, &ngx_posted_events);
+ }
+
return rc;
}

@@ -1835,6 +1860,33 @@ ngx_http_grpc_filter(void *data, ssize_t
rc = ngx_http_grpc_parse_frame(r, ctx, b);

if (rc == NGX_AGAIN) {
+
+ if (ctx->done) {
+
+ /*
+ * We have finished parsing the response and the
+ * remaining control frames. If there are unsent
+ * control frames, post a write event to send them.
+ */
+
+ if (ctx->out) {
+ ngx_post_event(u->peer.connection->write,
+ &ngx_posted_events);
+ return NGX_AGAIN;
+ }
+
+ u->length = 0;
+
+ if (ctx->in == NULL
+ && ctx->output_closed
+ && ctx->state == ngx_http_grpc_st_start)
+ {
+ u->keepalive = 1;
+ }
+
+ break;
+ }
+
return NGX_AGAIN;
}

@@ -1901,6 +1953,13 @@ ngx_http_grpc_filter(void *data, ssize_t
return NGX_ERROR;
}

+ if (ctx->stream_id && ctx->done) {
+ ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
+ "upstream sent frame for closed stream %ui",
+ ctx->stream_id);
+ return NGX_ERROR;
+ }
+
ctx->padding = 0;
}

@@ -1917,17 +1976,7 @@ ngx_http_grpc_filter(void *data, ssize_t
ctx->state = ngx_http_grpc_st_start;

if (ctx->flags & NGX_HTTP_V2_END_STREAM_FLAG) {
- u->length = 0;
-
- if (ctx->in == NULL
- && ctx->out == NULL
- && ctx->output_closed
- && b->last == b->pos)
- {
- u->keepalive = 1;
- }
-
- break;
+ ctx->done = 1;
}

continue;
@@ -2097,17 +2146,8 @@ ngx_http_grpc_filter(void *data, ssize_t
"grpc trailer done");

if (ctx->end_stream) {
- u->length = 0;
-
- if (ctx->in == NULL
- && ctx->out == NULL
- && ctx->output_closed
- && b->last == b->pos)
- {
- u->keepalive = 1;
- }
-
- return NGX_OK;
+ ctx->done = 1;
+ break;
}

ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
@@ -2124,6 +2164,10 @@ ngx_http_grpc_filter(void *data, ssize_t
return NGX_ERROR;
}

+ if (rc == NGX_HTTP_PARSE_HEADER_DONE) {
+ continue;
+ }
+
/* rc == NGX_AGAIN */

if (ctx->rest == 0) {
@@ -2240,17 +2284,7 @@ ngx_http_grpc_filter(void *data, ssize_t
ctx->state = ngx_http_grpc_st_start;

if (ctx->flags & NGX_HTTP_V2_END_STREAM_FLAG) {
- u->length = 0;
-
- if (ctx->in == NULL
- && ctx->out == NULL
- && ctx->output_closed
- && b->last == b->pos)
- {
- u->keepalive = 1;
- }
-
- break;
+ ctx->done = 1;
}
}

_______________________________________________
nginx-devel mailing list
nginx-devel@nginx.org
http://mailman.nginx.org/mailman/listinfo/nginx-devel
Subject Author Views Posted

[nginx] gRPC: improved keepalive handling.

Maxim Dounin 50 December 04, 2018 08:38AM



Sorry, you do not have permission to post/reply in this forum.

Online Users

Guests: 69
Record Number of Users: 6 on February 13, 2018
Record Number of Guests: 421 on December 02, 2018
Powered by nginx      Powered by FreeBSD      PHP Powered      Powered by MariaDB      ipv6 ready