Skip to content

Commit 3630d47

Browse files
author
Zizhong Zhang
committed
HTTP2 drain
1 parent 7527891 commit 3630d47

File tree

8 files changed

+68
-3
lines changed

8 files changed

+68
-3
lines changed

mgmt/RecordsConfig.cc

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1111,6 +1111,8 @@ static const RecordElement RecordsConfig[] =
11111111
// ###########
11121112
{RECT_CONFIG, "proxy.config.http.connect_ports", RECD_STRING, "443", RECU_DYNAMIC, RR_NULL, RECC_STR, "^(\\*|[[:digit:][:space:]]+)$", RECA_NULL}
11131113
,
1114+
{RECT_CONFIG, "proxy.config.http.http2_drain_timeout", RECD_INT, "0", RECU_RESTART_TS, RR_NULL, RECC_STR, "^[0-9]+$", RECA_NULL}
1115+
,
11141116
// ##########################
11151117
// # Various update periods #
11161118
// ##########################

proxy/Main.cc

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,8 @@ static int cmd_line_dprintf_level = 0; // default debug output level from ink_d
173173
static int poll_timeout = -1; // No value set.
174174
static int cmd_disable_freelist = 0;
175175

176+
static int http2_drain_timeout = 0;
177+
176178
static volatile bool sigusr1_received = false;
177179
static volatile bool sigusr2_received = false;
178180

@@ -460,6 +462,11 @@ proxy_signal_handler(int signo, siginfo_t *info, void *ctx)
460462
signal_crash_handler(signo, info, ctx);
461463
}
462464

465+
if (http2_drain_timeout) {
466+
http2_drain = true;
467+
sleep(http2_drain_timeout);
468+
}
469+
463470
shutdown_event_system = true;
464471
sleep(1);
465472
}
@@ -1688,6 +1695,8 @@ main(int /* argc ATS_UNUSED */, const char **argv)
16881695
::exit(0);
16891696
}
16901697

1698+
REC_ReadConfigInteger(http2_drain_timeout, "proxy.config.http.http2_drain_timeout");
1699+
16911700
// We need to do this early so we can initialize the Machine
16921701
// singleton, which depends on configuration values loaded in this.
16931702
// We want to initialize Machine as early as possible because it

proxy/http2/HTTP2.cc

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@
2828
#include "P_RecCore.h"
2929
#include "P_RecProcess.h"
3030

31+
volatile bool http2_drain = false;
32+
3133
const char *const HTTP2_CONNECTION_PREFACE = "PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n";
3234

3335
// Constant strings for pseudo headers

proxy/http2/HTTP2.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@ typedef unsigned Http2StreamId;
3838
// the flow control window can be come negative so we need to track it with a signed type.
3939
typedef int32_t Http2WindowSize;
4040

41+
extern volatile bool http2_drain;
42+
4143
extern const char *const HTTP2_CONNECTION_PREFACE;
4244
const size_t HTTP2_CONNECTION_PREFACE_LEN = 24;
4345

proxy/http2/Http2ClientSession.cc

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -297,6 +297,10 @@ Http2ClientSession::main_event_handler(int event, void *edata)
297297
schedule_event = nullptr;
298298
}
299299

300+
if (http2_drain && this->connection_state.get_shutdown_state() == NOT_INITATED) {
301+
send_connection_event(&this->connection_state, HTTP2_SESSION_EVENT_SHUTDOWN_INIT, this);
302+
}
303+
300304
switch (event) {
301305
case VC_EVENT_READ_COMPLETE:
302306
case VC_EVENT_READ_READY:

proxy/http2/Http2ClientSession.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,8 @@
4141
#define HTTP2_SESSION_EVENT_FINI (HTTP2_SESSION_EVENTS_START + 2)
4242
#define HTTP2_SESSION_EVENT_RECV (HTTP2_SESSION_EVENTS_START + 3)
4343
#define HTTP2_SESSION_EVENT_XMIT (HTTP2_SESSION_EVENTS_START + 4)
44+
#define HTTP2_SESSION_EVENT_SHUTDOWN_INIT (HTTP2_SESSION_EVENTS_START + 5)
45+
#define HTTP2_SESSION_EVENT_SHUTDOWN_CONT (HTTP2_SESSION_EVENTS_START + 6)
4446

4547
size_t const HTTP2_HEADER_BUFFER_SIZE_INDEX = CLIENT_CONNECTION_FIRST_READ_BUFFER_SIZE_INDEX;
4648

proxy/http2/Http2ConnectionState.cc

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -913,8 +913,33 @@ Http2ConnectionState::main_event_handler(int event, void *edata)
913913
}
914914
}
915915

916-
break;
917-
}
916+
} break;
917+
918+
// Initiate a gracefull shutdown
919+
case HTTP2_SESSION_EVENT_SHUTDOWN_INIT: {
920+
SCOPED_MUTEX_LOCK(lock, this->mutex, this_ethread());
921+
if (shutdown_state != NOT_INITATED)
922+
break;
923+
shutdown_state = INITIATED;
924+
// [RFC 7540] 6.8. GOAWAY
925+
// A server that is attempting to gracefully shut down a
926+
// connection SHOULD send an initial GOAWAY frame with the last stream
927+
// identifier set to 2^31-1 and a NO_ERROR code.
928+
send_goaway_frame(INT32_MAX, Http2ErrorCode::HTTP2_ERROR_NO_ERROR);
929+
// After allowing time for any in-flight stream creation (at least one round-trip time),
930+
this_ethread()->schedule_in((Continuation *)this, HRTIME_SECONDS(2), HTTP2_SESSION_EVENT_SHUTDOWN_CONT);
931+
} break;
932+
933+
// Continue a gracefull shutdown
934+
case HTTP2_SESSION_EVENT_SHUTDOWN_CONT: {
935+
SCOPED_MUTEX_LOCK(lock, this->mutex, this_ethread());
936+
if (shutdown_state != INITIATED)
937+
break;
938+
shutdown_state = IN_PROGREASS;
939+
// [RFC 7540] 6.8. GOAWAY
940+
// ..., the server can send another GOAWAY frame with an updated last stream identifier
941+
send_goaway_frame(latest_streamid_in, Http2ErrorCode::HTTP2_ERROR_NO_ERROR);
942+
} break;
918943

919944
default:
920945
DebugHttp2Con(ua_session, "unexpected event=%d edata=%p", event, edata);
@@ -1120,6 +1145,9 @@ Http2ConnectionState::release_stream(Http2Stream *stream)
11201145
// We were shutting down, go ahead and terminate the session
11211146
ua_session->destroy();
11221147
ua_session = nullptr;
1148+
} else if (total_client_streams_count == 0 && http2_drain && ua_session && stream) {
1149+
send_goaway_frame(stream->get_id(), Http2ErrorCode::HTTP2_ERROR_NO_ERROR);
1150+
Note("[Http2ConnectionState::release_stream]: draining http2 connection, GOAWAY is sent");
11231151
}
11241152
}
11251153

proxy/http2/Http2ConnectionState.h

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@ enum Http2SendADataFrameResult {
3838
HTTP2_SEND_A_DATA_FRAME_DONE = 3,
3939
};
4040

41+
enum Http2ShutdownState { NOT_INITATED, INITIATED, IN_PROGREASS };
42+
4143
class Http2ConnectionSettings
4244
{
4345
public:
@@ -126,7 +128,8 @@ class Http2ConnectionState : public Continuation
126128
continued_stream_id(0),
127129
_scheduled(false),
128130
fini_received(false),
129-
recursion(0)
131+
recursion(0),
132+
shutdown_state(NOT_INITATED)
130133
{
131134
SET_HANDLER(&Http2ConnectionState::main_event_handler);
132135
}
@@ -265,6 +268,18 @@ class Http2ConnectionState : public Continuation
265268
}
266269
}
267270

271+
Http2ShutdownState
272+
get_shutdown_state() const
273+
{
274+
return shutdown_state;
275+
}
276+
277+
void
278+
set_shutdown_state(Http2ShutdownState state)
279+
{
280+
shutdown_state = state;
281+
}
282+
268283
private:
269284
Http2ConnectionState(const Http2ConnectionState &); // noncopyable
270285
Http2ConnectionState &operator=(const Http2ConnectionState &); // noncopyable
@@ -303,6 +318,7 @@ class Http2ConnectionState : public Continuation
303318
bool _scheduled;
304319
bool fini_received;
305320
int recursion;
321+
Http2ShutdownState shutdown_state;
306322
};
307323

308324
#endif // __HTTP2_CONNECTION_STATE_H__

0 commit comments

Comments
 (0)