terrible horrible graceful http restarts

This commit is contained in:
Joe Bryan 2018-06-12 19:08:10 -04:00
parent f4c90aa7bc
commit 28d9c769cd
2 changed files with 184 additions and 32 deletions

View File

@ -78,10 +78,18 @@
c3_s por_s; // running port
c3_o sec; // logically secure
c3_o lop; // loopback-only
c3_o liv; // c3n == shutting down
struct _u3_hcon* hon_u; // connection list
struct _u3_http* nex_u; // next in list
} u3_http;
/* u3_hfig: general http configuration
*/
typedef struct _u3_hfig {
u3_noun fig; // config from %eyre
uv_timer_t* tim_u; // hard restart timer
} u3_hfig;
/* u3_proxy_type: proxy connection downstream type
*/
typedef enum {
@ -580,6 +588,7 @@
c3_c* dir_c; // pier path (no trailing /)
c3_d now_d; // event tick
uv_loop_t* lup_u; // libuv event loop
u3_hfig fig_u; // http configuration
u3_http* htp_u; // http servers
u3_cttp ctp_u; // http clients
u3_utel tel_u; // telnet listener

View File

@ -33,6 +33,10 @@ static void _proxy_serv_close(u3_prox* lis_u);
static u3_prox* _proxy_serv_new(u3_http* htp_u, c3_s por_s, c3_o sec);
static u3_prox* _proxy_serv_start(u3_prox* lis_u);
static void _http_conn_close(u3_hcon* hon_u);
static void _http_serv_close_hard(u3_http* htp_u);
static void _http_serv_start_all(void);
static const c3_i TCP_BACKLOG = 16;
/* _http_vec_to_meth(): convert h2o_iovec_t to meth
@ -237,7 +241,15 @@ _http_req_unlink(u3_hreq* req_u)
static void
_http_req_free(u3_hreq* req_u)
{
u3_hcon* hon_u = req_u->hon_u;
u3_http* htp_u = hon_u->htp_u;
_http_req_unlink(req_u);
if ( (c3n == htp_u->liv) && (0 == hon_u->req_u) ) {
_http_conn_close(hon_u);
}
free(req_u);
}
@ -496,6 +508,7 @@ static void
_http_conn_free(uv_handle_t* han_t)
{
u3_hcon* hon_u = (u3_hcon*)han_t;
u3_http* htp_u = hon_u->htp_u;
while ( 0 != hon_u->req_u ) {
u3_hreq* req_u = hon_u->req_u;
@ -508,6 +521,11 @@ _http_conn_free(uv_handle_t* han_t)
}
_http_conn_unlink(hon_u);
if ( (c3n == htp_u->liv) && (0 == htp_u->hon_u) ) {
_http_serv_close_hard(htp_u);
}
free(hon_u);
}
@ -601,6 +619,8 @@ _http_serv_unlink(u3_http* htp_u)
static void
_http_serv_free(u3_http* htp_u)
{
uL(fprintf(uH, "_http_serv_free\n"));
_http_serv_unlink(htp_u);
while ( 0 != htp_u->hon_u ) {
@ -611,24 +631,61 @@ _http_serv_free(u3_http* htp_u)
if ( 0 != htp_u->h2o_u ) {
h2o_config_dispose(&((u3_h2o_serv*)htp_u->h2o_u)->fig_u);
free(htp_u->h2o_u);
htp_u->h2o_u = 0;
}
if ( 0 != htp_u->rox_u ) {
_proxy_serv_close(htp_u->rox_u);
htp_u->rox_u = 0;
}
// XX groace
if ( (c3n == htp_u->liv) && (0 == u3_Host.htp_u) ) {
_http_serv_start_all();
}
free(htp_u);
}
/* _http_serv_close(): close http server.
/* _http_serv_close_hard(): close http server.
*/
static void
_http_serv_close(u3_http* htp_u)
_http_serv_close_hard(u3_http* htp_u)
{
uL(fprintf(uH, "_http_serv_close_hard\n"));
uv_close((uv_handle_t*)&htp_u->wax_u,
(uv_close_cb)_http_serv_free);
}
/* _http_serv_close_soft(): close http server gracefully.
*/
static void
_http_serv_close_soft(u3_http* htp_u)
{
uL(fprintf(uH, "_http_serv_close_soft\n"));
u3_h2o_serv* h2o_u = htp_u->h2o_u;
h2o_context_request_shutdown(&h2o_u->ctx_u);
htp_u->liv = c3n;
u3_hcon* hon_u = htp_u->hon_u;
while ( 0 != hon_u ) {
u3_hcon* nex_u = hon_u->nex_u;
if ( 0 == hon_u->req_u ) {
_http_conn_close(hon_u);
}
hon_u = nex_u;
}
if ( 0 != htp_u->rox_u ) {
_proxy_serv_close(htp_u->rox_u);
htp_u->rox_u = 0;
}
}
/* _http_serv_new(): create new http server.
*/
static u3_http*
@ -640,6 +697,7 @@ _http_serv_new(c3_s por_s, c3_o sec, c3_o lop)
htp_u->por_s = por_s;
htp_u->sec = sec;
htp_u->lop = lop;
htp_u->liv = c3y;
htp_u->h2o_u = 0;
htp_u->rox_u = 0;
htp_u->hon_u = 0;
@ -655,6 +713,10 @@ _http_serv_new(c3_s por_s, c3_o sec, c3_o lop)
static void
_http_serv_accept(u3_http* htp_u)
{
if ( c3n == htp_u->liv ) {
return;
}
u3_hcon* hon_u = _http_conn_new(htp_u);
uv_tcp_init(u3L, &hon_u->wax_u);
@ -956,22 +1018,28 @@ u3_http_ef_thou(c3_l sev_l,
u3z(rep);
}
void
u3_http_ef_form(u3_noun fig)
static void
_http_serv_start_all(void)
{
// flag that servers are coming down
// stop accepting connections
// check on request done / connection close
// investigate h2o_context_request_shutdown
uL(fprintf(uH, "_http_serv_start_all\n"));
uL(fprintf(uH, "true %d\n", 0 == 0));
uL(fprintf(uH, "no existing servers %d\n", 0 == u3_Host.htp_u));
u3_Host.htp_u = 0;
if ( 0 != u3_Host.fig_u.tim_u ) {
uv_timer_stop(u3_Host.fig_u.tim_u);
free(u3_Host.fig_u.tim_u);
u3_Host.fig_u.tim_u = 0;
}
u3_http* htp_u;
c3_s por_s;
for ( htp_u = u3_Host.htp_u; htp_u; htp_u = htp_u->nex_u ) {
_http_serv_close(htp_u);
}
u3_noun fig = u3_Host.fig_u.fig;
// XX am i supposed to cell test every axis?
// XX validate / test axes?
u3_noun sec = u3h(fig);
u3_noun lob = u3t(fig);
u3_noun pro = u3h(lob);
@ -980,9 +1048,10 @@ u3_http_ef_form(u3_noun fig)
// HTTPS server.
// if ( u3_nul != sec ) {
// XX unpack/parse sec
// // XX unpack/parse sec
// u3_noun key = u3h(u3t(sec));
// u3_noun cer = u3t(u3t(sec));
// // XX stash at u3_Host.fig_u.tls_u
// SSL_CTX* tls_u = _http_init_tls(key, cer);
SSL_CTX* tls_u = _http_init_tls();
@ -1016,24 +1085,6 @@ u3_http_ef_form(u3_noun fig)
// never proxied
}
u3z(fig);
}
/* u3_http_io_init(): initialize http I/O.
*/
void
u3_http_io_init()
{
u3_http_ef_form(u3nq(u3_nul, c3y, c3y, c3y));
}
/* u3_http_io_talk(): start http I/O.
*/
void
u3_http_io_talk()
{
u3_http* htp_u;
for ( htp_u = u3_Host.htp_u; htp_u; htp_u = htp_u->nex_u ) {
_http_serv_start(htp_u);
}
@ -1041,6 +1092,90 @@ u3_http_io_talk()
_http_write_ports_file(u3_Host.dir_c);
}
static void
_http_serv_restart_cb(uv_timer_t* tim_u)
{
u3_http* htp_u;
// XX printf
for ( htp_u = u3_Host.htp_u; htp_u; htp_u = htp_u->nex_u ) {
_http_serv_close_hard(htp_u);
}
_http_serv_start_all();
free(tim_u);
}
static void
_http_serv_restart(void)
{
uL(fprintf(uH, "_http_serv_restart\n"));
u3_http* htp_u;
if ( 0 == u3_Host.htp_u ) {
_http_serv_start_all();
return;
}
uL(fprintf(uH, "http: restarting servers to apply configuration\n"));
for ( htp_u = u3_Host.htp_u; htp_u; htp_u = htp_u->nex_u ) {
// flag that servers are coming down
// stop accepting connections
_http_serv_close_soft(htp_u);
}
u3_Host.fig_u.tim_u = c3_malloc(sizeof(uv_timer_t));
uv_timer_init(u3L, u3_Host.fig_u.tim_u);
uv_timer_start(u3_Host.fig_u.tim_u, _http_serv_restart_cb, 0, 0);
_http_release_ports_file(u3_Host.dir_c);
}
void
u3_http_ef_form(u3_noun fig)
{
// XX validate now?
u3z(u3_Host.fig_u.fig);
u3_Host.fig_u.fig = fig;
_http_serv_restart();
}
static void
_http_serv_test_restart_cb(uv_timer_t* tim_u)
{
uL(fprintf(uH, "_http_serv_test_restart_cb\n"));
_http_serv_restart();
free(tim_u);
}
/* u3_http_io_init(): initialize http I/O.
*/
void
u3_http_io_init(void)
{
// XX avoid u3_noun foo; u3z(foo); is this necessary?
u3_Host.fig_u.fig = u3_none;
uv_timer_t* tim_u = c3_malloc(sizeof(*tim_u));
uv_timer_init(u3L, tim_u);
uv_timer_start(tim_u, _http_serv_test_restart_cb, 60 * 1000, 0);
}
/* u3_http_io_talk(): start http I/O.
*/
void
u3_http_io_talk(void)
{
// XX remove this once %form is actually wired up
u3_http_ef_form(u3nq(u3_nul, c3y, c3y, c3y));
}
/* u3_http_io_poll(): poll kernel for http I/O.
*/
void
@ -1053,7 +1188,15 @@ u3_http_io_poll(void)
void
u3_http_io_exit(void)
{
// XX shutdown servers cleanly
// Note: nothing in this codepath can print to uH!
// it will seriously mess up your terminal
// u3_http* htp_u;
// for ( htp_u = u3_Host.htp_u; htp_u; htp_u = htp_u->nex_u ) {
// _http_serv_close_hard(htp_u);
// }
_http_release_ports_file(u3_Host.dir_c);
}