From 1e79617d2f8eec50a1bca0931a689e5f3b8ecc82 Mon Sep 17 00:00:00 2001 From: Kai Burjack Date: Wed, 28 Jan 2026 13:44:28 +0100 Subject: [PATCH] feat: add connection draining during shutdown --- bin/varnishd/cache/cache_cli.c | 30 ++++++++++++- bin/varnishd/cache/cache_main.c | 7 ++- bin/varnishd/cache/cache_pool.c | 26 +++++++++++ bin/varnishd/cache/cache_session.c | 15 +++++++ bin/varnishd/cache/cache_varnishd.h | 4 ++ bin/varnishd/cache/cache_vcl.c | 21 +++++++++ bin/varnishd/cache/cache_wrk.c | 4 ++ bin/varnishd/http1/cache_http1_deliver.c | 7 +++ bin/varnishd/mgt/mgt.h | 1 + bin/varnishd/mgt/mgt_child.c | 12 ++++-- bin/varnishd/mgt/mgt_main.c | 55 +++++++++++++++++++++++- bin/varnishtest/tests/b00099.vtc | 46 ++++++++++++++++++++ bin/varnishtest/tests/b00100.vtc | 26 +++++++++++ bin/varnishtest/tests/b00101.vtc | 48 +++++++++++++++++++++ bin/varnishtest/tests/b00102.vtc | 40 +++++++++++++++++ bin/varnishtest/tests/b00103.vtc | 26 +++++++++++ bin/varnishtest/tests/b00104.vtc | 26 +++++++++++ include/tbl/cli_cmds.h | 10 +++++ include/tbl/params.h | 18 ++++++++ include/tbl/sess_close.h | 1 + lib/libvsc/VSC_main.vsc | 7 +++ 21 files changed, 423 insertions(+), 7 deletions(-) create mode 100644 bin/varnishtest/tests/b00099.vtc create mode 100644 bin/varnishtest/tests/b00100.vtc create mode 100644 bin/varnishtest/tests/b00101.vtc create mode 100644 bin/varnishtest/tests/b00102.vtc create mode 100644 bin/varnishtest/tests/b00103.vtc create mode 100644 bin/varnishtest/tests/b00104.vtc diff --git a/bin/varnishd/cache/cache_cli.c b/bin/varnishd/cache/cache_cli.c index 3670a1bc412..41afefb652c 100644 --- a/bin/varnishd/cache/cache_cli.c +++ b/bin/varnishd/cache/cache_cli.c @@ -39,6 +39,7 @@ #include "config.h" #include "cache_varnishd.h" +#include "acceptor/cache_acceptor.h" #include "common/heritage.h" #include "vcli_serve.h" @@ -108,16 +109,43 @@ CLI_Run(void) cli->auth = 255; // Non-zero to disable paranoia in vcli_serve do { - i = VCLS_Poll(cache_cls, cli, -1); + /* + * When draining, use short poll timeout so we can check + * if all connections have been closed. + */ + i = VCLS_Poll(cache_cls, cli, cache_draining ? 1000 : -1); + if (cache_draining && SES_ActiveCount() == 0 && VCL_Drained()) { + VSL(SLT_CLI, NO_VXID, + "All connections drained, shutting down"); + break; + } } while (i == 0); VSL(SLT_CLI, NO_VXID, "EOF on CLI connection, worker stops"); } +static void v_matchproto_(cli_func_t) +ccf_drain(struct cli *cli, const char * const *av, void *priv) +{ + (void)cli; + (void)av; + (void)priv; + cache_draining = 1; + /* Enable rapid VCL release so idle workers release VCL immediately */ + cache_param->debug_bits[DBG_VCLREL >> 3] |= + (0x80 >> (DBG_VCLREL & 7)); + /* Stop accepting new connections immediately */ + VCA_Shutdown(); + /* Wake up idle workers so they release VCL references */ + Pool_WakeIdle(); + VCLI_Out(cli, "Connection draining enabled, new connections refused"); +} + /*--------------------------------------------------------------------*/ static struct cli_proto cli_cmds[] = { { CLICMD_PING, "i", VCLS_func_ping, VCLS_func_ping_json }, { CLICMD_HELP, "i", VCLS_func_help, VCLS_func_help_json }, + { CLICMD_SERVER_DRAIN, "", ccf_drain }, { NULL } }; diff --git a/bin/varnishd/cache/cache_main.c b/bin/varnishd/cache/cache_main.c index 95ed67244fb..cca6be820ae 100644 --- a/bin/varnishd/cache/cache_main.c +++ b/bin/varnishd/cache/cache_main.c @@ -54,6 +54,7 @@ #include "hash/hash_slinger.h" volatile struct params *cache_param; +volatile unsigned cache_draining = 0; static pthread_mutex_t cache_vrnd_mtx; static vtim_dur shutdown_delay = 0; @@ -557,9 +558,13 @@ child_main(int sigmagic, size_t altstksz) if (shutdown_delay > 0) VTIM_sleep(shutdown_delay); - VCA_Shutdown(); + /* If draining, VCA_Shutdown was already called in ccf_drain */ + if (!cache_draining) + VCA_Shutdown(); BAN_Shutdown(); STV_warn(); + /* Wake up any idle workers so they release VCL references */ + Pool_WakeIdle(); VCL_Shutdown(); EXP_Shutdown(); STV_close(); diff --git a/bin/varnishd/cache/cache_pool.c b/bin/varnishd/cache/cache_pool.c index 9933365c9d7..cc7a25ad3c2 100644 --- a/bin/varnishd/cache/cache_pool.c +++ b/bin/varnishd/cache/cache_pool.c @@ -75,6 +75,32 @@ Pool_TrySumstat(const struct worker *wrk) return (1); } +/*-------------------------------------------------------------------- + * Wake up all idle workers so they can release VCL references quickly. + * Called when draining starts. + */ + +void +Pool_WakeIdle(void) +{ + struct pool *pp; + struct pool_task *pt; + struct worker *wrk; + + Lck_Lock(&pool_mtx); + VTAILQ_FOREACH(pp, &pools, list) { + CHECK_OBJ_NOTNULL(pp, POOL_MAGIC); + Lck_Lock(&pp->mtx); + VTAILQ_FOREACH(pt, &pp->idle_queue, list) { + AZ(pt->func); + CAST_OBJ_NOTNULL(wrk, pt->priv, WORKER_MAGIC); + PTOK(pthread_cond_signal(&wrk->cond)); + } + Lck_Unlock(&pp->mtx); + } + Lck_Unlock(&pool_mtx); +} + /*-------------------------------------------------------------------- * Facility for scheduling a task on any convenient pool. */ diff --git a/bin/varnishd/cache/cache_session.c b/bin/varnishd/cache/cache_session.c index e50c8f56c88..ffa6e749f6f 100644 --- a/bin/varnishd/cache/cache_session.c +++ b/bin/varnishd/cache/cache_session.c @@ -52,6 +52,9 @@ #include "vtim.h" #include "waiter/waiter.h" +/* Count of active sessions (for drain detection) */ +static volatile unsigned n_sess_active = 0; + static const struct { const char *type; } sess_attr[SA_LAST] = { @@ -447,6 +450,7 @@ SES_New(struct pool *pp) sp->idle_send_timeout = NAN; Lck_New(&sp->mtx, lck_sess); CHECK_OBJ_NOTNULL(sp, SESS_MAGIC); + n_sess_active++; return (sp); } @@ -689,6 +693,8 @@ SES_Rel(struct sess *sp) #ifdef ENABLE_WORKSPACE_EMULATOR WS_Rollback(sp->ws, 0); #endif + assert(n_sess_active > 0); + n_sess_active--; MPL_Free(sp->pool->mpl_sess, sp); } @@ -720,3 +726,12 @@ SES_DestroyPool(struct pool *pp) MPL_Destroy(&pp->mpl_sess); Waiter_Destroy(&pp->waiter); } + +/* + * Return count of active sessions (for drain detection). + */ +unsigned +SES_ActiveCount(void) +{ + return (n_sess_active); +} diff --git a/bin/varnishd/cache/cache_varnishd.h b/bin/varnishd/cache/cache_varnishd.h index a2edf20833f..7c0f01e307c 100644 --- a/bin/varnishd/cache/cache_varnishd.h +++ b/bin/varnishd/cache/cache_varnishd.h @@ -122,6 +122,7 @@ typedef enum htc_status_e htc_complete_f(struct http_conn *); /* -------------------------------------------------------------------*/ extern volatile struct params * cache_param; +extern volatile unsigned cache_draining; /* ------------------------------------------------------------------- * The VCF facility is deliberately undocumented, use at your peril. @@ -414,6 +415,7 @@ int Pool_Task_Arg(struct worker *, enum task_prio, task_func_t *, const void *arg, size_t arg_len); void Pool_Sumstat(const struct worker *w); int Pool_TrySumstat(const struct worker *wrk); +void Pool_WakeIdle(void); void Pool_PurgeStat(unsigned nobj); int Pool_Task_Any(struct pool_task *task, enum task_prio prio); void pan_pool(struct vsb *); @@ -456,6 +458,7 @@ void SES_DestroyPool(struct pool *); void SES_Wait(struct sess *, const struct transport *); void SES_Ref(struct sess *sp); void SES_Rel(struct sess *sp); +unsigned SES_ActiveCount(void); void HTC_Status(enum htc_status_e, const char **, const char **); void HTC_RxInit(struct http_conn *htc, struct ws *ws); @@ -504,6 +507,7 @@ struct vsb *VCL_Rel_CliCtx(struct vrt_ctx **); void VCL_Panic(struct vsb *, const char *nm, const struct vcl *); void VCL_Poll(void); void VCL_Init(void); +int VCL_Drained(void); void VCL_Shutdown(void); #define VCL_MET_MAC(l,u,t,b) \ diff --git a/bin/varnishd/cache/cache_vcl.c b/bin/varnishd/cache/cache_vcl.c index 2c219573934..e7c3c1ddb77 100644 --- a/bin/varnishd/cache/cache_vcl.c +++ b/bin/varnishd/cache/cache_vcl.c @@ -1288,6 +1288,27 @@ VCL_Init(void) VSL_Setup(&vsl_cli, NULL, 0); } +/* + * Check if all VCL references have been released. + * Returns 1 if all VCLs have busy == 0, 0 otherwise. + */ +int +VCL_Drained(void) +{ + struct vcl *vcl; + int drained = 1; + + Lck_Lock(&vcl_mtx); + VTAILQ_FOREACH(vcl, &vcl_head, list) { + if (vcl->busy) { + drained = 0; + break; + } + } + Lck_Unlock(&vcl_mtx); + return (drained); +} + void VCL_Shutdown(void) { diff --git a/bin/varnishd/cache/cache_wrk.c b/bin/varnishd/cache/cache_wrk.c index 97190433780..72f73be22c6 100644 --- a/bin/varnishd/cache/cache_wrk.c +++ b/bin/varnishd/cache/cache_wrk.c @@ -446,6 +446,10 @@ Pool_Work_Thread(struct pool *pp, struct worker *wrk) tmo = INFINITY; else if (DO_DEBUG(DBG_VTC_MODE)) tmo = now + 1.; + else if (cache_draining) + /* During draining, use short timeout + * to release VCL quickly */ + tmo = now + 1.; else tmo = now + 60.; (void)Lck_CondWaitUntil( diff --git a/bin/varnishd/http1/cache_http1_deliver.c b/bin/varnishd/http1/cache_http1_deliver.c index edb32573e7e..228280d4db9 100644 --- a/bin/varnishd/http1/cache_http1_deliver.c +++ b/bin/varnishd/http1/cache_http1_deliver.c @@ -92,6 +92,13 @@ V1D_Deliver(struct req *req, int sendbody) } else if (!http_GetHdr(req->resp, H_Connection, NULL)) http_SetHeader(req->resp, "Connection: keep-alive"); + /* If draining, force Connection: close */ + if (cache_draining && req->doclose == SC_NULL) { + req->doclose = SC_DRAIN; + http_Unset(req->resp, H_Connection); + http_SetHeader(req->resp, "Connection: close"); + } + CHECK_OBJ_NOTNULL(req->wrk, WORKER_MAGIC); v1l = V1L_Open(req->wrk->aws, &req->sp->fd, req->vsl, diff --git a/bin/varnishd/mgt/mgt.h b/bin/varnishd/mgt/mgt.h index 8d86df2eeee..7d2c0a1a2c6 100644 --- a/bin/varnishd/mgt/mgt.h +++ b/bin/varnishd/mgt/mgt.h @@ -64,6 +64,7 @@ struct vclprog; extern struct vev_root *mgt_evb; extern unsigned d_flag; extern int exit_status; +extern int mgt_draining; /* option=value argument parse helper */ static inline const char * diff --git a/bin/varnishd/mgt/mgt_child.c b/bin/varnishd/mgt/mgt_child.c index 14992679745..8524185368d 100644 --- a/bin/varnishd/mgt/mgt_child.c +++ b/bin/varnishd/mgt/mgt_child.c @@ -628,11 +628,17 @@ mgt_reap_child(void) exit(1); } - if (child_state == CH_DIED && mgt_param.auto_restart) + if (child_state == CH_DIED && mgt_param.auto_restart && !mgt_draining) mgt_launch_child(NULL); - else if (child_state == CH_DIED) + else if (child_state == CH_DIED) { child_state = CH_STOPPED; - else if (child_state == CH_STOPPING) + if (mgt_draining) { + /* Child exited during drain, proceed with shutdown */ + MGT_Complain(C_INFO, + "Child exited during drain, proceeding with shutdown"); + (void)raise(SIGTERM); + } + } else if (child_state == CH_STOPPING) child_state = CH_STOPPED; } diff --git a/bin/varnishd/mgt/mgt_main.c b/bin/varnishd/mgt/mgt_main.c index 28ca03e19dd..dcd99168dc6 100644 --- a/bin/varnishd/mgt/mgt_main.c +++ b/bin/varnishd/mgt/mgt_main.c @@ -74,6 +74,8 @@ struct vsb *vident; struct VSC_mgt *VSC_C_mgt; static int I_fd = -1; static char *workdir; +int mgt_draining = 0; +static struct vev *drain_timer = NULL; static struct vfil_path *vcl_path = NULL; @@ -444,17 +446,66 @@ mgt_eric_im_done(int eric_fd, unsigned u) /*--------------------------------------------------------------------*/ +static int v_matchproto_(vev_cb_f) +mgt_drain_timeout(const struct vev *e, int what) +{ + (void)e; + (void)what; + MGT_Complain(C_INFO, "Drain timeout reached, stopping child"); + MCH_Stop_Child(); + (void)raise(SIGTERM); /* Trigger signal handler to exit event loop */ + return (1); /* Remove this timeout event */ +} + static int v_matchproto_(vev_cb_f) mgt_sigint(const struct vev *e, int what) { + unsigned status; + char *p; (void)what; MGT_Complain(C_INFO, "Manager got %s from PID %jd", e->name, (intmax_t)e->siginfo->si_pid); (void)fflush(stdout); - if (MCH_Running()) + + if (!MCH_Running()) + return (-42); + + /* If drain_timeout is 0, do immediate shutdown */ + if (mgt_param.drain_timeout == 0) { MCH_Stop_Child(); - return (-42); + return (-42); + } + + /* If already draining, proceed to shutdown */ + if (mgt_draining) { + MGT_Complain(C_INFO, "Already draining, stopping child"); + MCH_Stop_Child(); + return (-42); + } + + /* Send drain command to child */ + if (mgt_cli_askchild(&status, &p, "drain\n")) { + MGT_Complain(C_ERR, "Failed to send drain command: %s", p); + free(p); + MCH_Stop_Child(); + return (-42); + } + free(p); + + mgt_draining = 1; + MGT_Complain(C_INFO, "Connection draining started, timeout %.0f seconds", + mgt_param.drain_timeout); + + /* Set up drain timeout event */ + drain_timer = VEV_Alloc(); + AN(drain_timer); + drain_timer->name = "drain_timeout"; + drain_timer->timeout = mgt_param.drain_timeout; + drain_timer->callback = mgt_drain_timeout; + AZ(VEV_Start(mgt_evb, drain_timer)); + + return (0); /* Keep event loop running */ } /*--------------------------------------------------------------------*/ diff --git a/bin/varnishtest/tests/b00099.vtc b/bin/varnishtest/tests/b00099.vtc new file mode 100644 index 00000000000..e21e2a61281 --- /dev/null +++ b/bin/varnishtest/tests/b00099.vtc @@ -0,0 +1,46 @@ +varnishtest "Test connection draining adds Connection: close" + +# Test that during draining, responses include Connection: close header +# The connection must be established BEFORE drain starts (VCA_Shutdown stops new connections) + +barrier b1 cond 2 +barrier b2 cond 2 + +server s1 { + rxreq + # Signal that backend received the request + barrier b1 sync + # Wait for drain to start before responding + barrier b2 sync + txresp -body "response during drain" +} -start + +varnish v1 -arg "-p drain_timeout=10" -vcl+backend { } -start + +# Start request (establishes connection) +client c1 { + txreq -url "/" + rxresp + expect resp.status == 200 + expect resp.body == "response during drain" + # Response during drain should have Connection: close + expect resp.http.Connection == "close" +} -start + +# Wait for request to reach backend (connection is now established) +barrier b1 sync + +# Now start draining - connection already exists +shell "kill -15 ${v1_pid}" + +# Small delay for drain to initialize +delay 0.1 + +# Signal backend to respond +barrier b2 sync + +# Wait for client to complete +client c1 -wait + +# Use -cleanup since varnish will exit on its own after drain completes +varnish v1 -cleanup diff --git a/bin/varnishtest/tests/b00100.vtc b/bin/varnishtest/tests/b00100.vtc new file mode 100644 index 00000000000..71826d75d29 --- /dev/null +++ b/bin/varnishtest/tests/b00100.vtc @@ -0,0 +1,26 @@ +varnishtest "Test SIGTERM triggers connection draining" + +# Test that SIGTERM with drain_timeout > 0 triggers draining +# and the child exits cleanly + +server s1 { + rxreq + txresp -body "response" +} -start + +varnish v1 -arg "-p drain_timeout=5" -vcl+backend { } -start + +# Verify varnish is running +client c1 { + txreq -url "/" + rxresp + expect resp.status == 200 +} -run + +server s1 -wait + +# Send SIGTERM to trigger draining +shell "kill -15 ${v1_pid}" + +# Use -cleanup since varnish will exit on its own after drain completes +varnish v1 -cleanup diff --git a/bin/varnishtest/tests/b00101.vtc b/bin/varnishtest/tests/b00101.vtc new file mode 100644 index 00000000000..a5116140f96 --- /dev/null +++ b/bin/varnishtest/tests/b00101.vtc @@ -0,0 +1,48 @@ +varnishtest "Test draining waits for active request to complete" + +# Test that draining waits for an in-flight request to complete +# before the child exits + +barrier b1 cond 2 +barrier b2 cond 2 + +server s1 { + rxreq + # Signal that we received the request + barrier b1 sync + # Wait for drain to be confirmed started + barrier b2 sync + # Respond after drain started + delay 0.3 + txresp -body "completed during drain" +} -start + +varnish v1 -arg "-p drain_timeout=10" -vcl+backend { } -start + +# Start a request that will be in-flight when drain starts +client c1 { + txreq -url "/" + rxresp + expect resp.status == 200 + expect resp.body == "completed during drain" + # Response during drain should have Connection: close + expect resp.http.Connection == "close" +} -start + +# Wait for request to reach backend +barrier b1 sync + +# Start drain while request is in progress +shell "kill -15 ${v1_pid}" + +# Small delay for drain to start +delay 0.1 + +# Signal server to respond +barrier b2 sync + +# Wait for client to complete +client c1 -wait + +# Use -cleanup since varnish will exit on its own after drain completes +varnish v1 -cleanup diff --git a/bin/varnishtest/tests/b00102.vtc b/bin/varnishtest/tests/b00102.vtc new file mode 100644 index 00000000000..20d090166ce --- /dev/null +++ b/bin/varnishtest/tests/b00102.vtc @@ -0,0 +1,40 @@ +varnishtest "Test drain timeout still waits for active requests" + +# Test that even after drain_timeout expires, Varnish waits for +# active requests to complete before shutting down + +barrier b1 cond 2 + +server s1 { + rxreq + # Signal that request was received + barrier b1 sync + # Hold the connection open longer than drain timeout + delay 3 + txresp -body "completed after drain timeout" +} -start + +varnish v1 -arg "-p drain_timeout=1" -vcl+backend { } -start + +# Start a request that will be in-flight when drain starts +client c1 { + txreq -url "/" + rxresp + # Request should complete even after drain timeout expires + expect resp.status == 200 + expect resp.body == "completed after drain timeout" + # Response during drain should have Connection: close + expect resp.http.Connection == "close" +} -start + +# Wait for request to reach backend +barrier b1 sync + +# Start drain via SIGTERM (drain_timeout=1s, but backend delays 3s) +shell "kill -15 ${v1_pid}" + +# Wait for client - request should complete successfully +client c1 -wait + +# Use -cleanup since varnish will exit on its own +varnish v1 -cleanup diff --git a/bin/varnishtest/tests/b00103.vtc b/bin/varnishtest/tests/b00103.vtc new file mode 100644 index 00000000000..1c45e6c8bab --- /dev/null +++ b/bin/varnishtest/tests/b00103.vtc @@ -0,0 +1,26 @@ +varnishtest "Test drain_timeout=0 does immediate shutdown" + +# Test that with drain_timeout=0, SIGTERM causes immediate shutdown +# without entering drain mode + +server s1 { + rxreq + txresp -body "response" +} -start + +varnish v1 -arg "-p drain_timeout=0" -vcl+backend { } -start + +# Verify varnish is running +client c1 { + txreq -url "/" + rxresp + expect resp.status == 200 +} -run + +server s1 -wait + +# Send SIGTERM - should cause immediate shutdown (drain_timeout=0) +shell "kill -15 ${v1_pid}" + +# Use -cleanup since varnish will exit on its own +varnish v1 -cleanup diff --git a/bin/varnishtest/tests/b00104.vtc b/bin/varnishtest/tests/b00104.vtc new file mode 100644 index 00000000000..5a4cb1cde79 --- /dev/null +++ b/bin/varnishtest/tests/b00104.vtc @@ -0,0 +1,26 @@ +varnishtest "Test basic connection draining" + +# Basic test: Varnish exits cleanly when SIGTERM is sent with drain_timeout > 0 + +server s1 { + rxreq + txresp -body "hello" +} -start + +varnish v1 -arg "-p drain_timeout=5" -vcl+backend { } -start + +# Verify varnish is working +client c1 { + txreq + rxresp + expect resp.status == 200 + expect resp.body == "hello" +} -run + +server s1 -wait + +# Send SIGTERM - this triggers draining +shell "kill -15 ${v1_pid}" + +# Use -cleanup since varnish will exit on its own after drain completes +varnish v1 -cleanup diff --git a/include/tbl/cli_cmds.h b/include/tbl/cli_cmds.h index dd2235935dd..43e95f50a80 100644 --- a/include/tbl/cli_cmds.h +++ b/include/tbl/cli_cmds.h @@ -216,6 +216,16 @@ CLI_CMD(SERVER_STOP, 0, 0 ) +CLI_CMD(SERVER_DRAIN, + "drain", + "drain", + "Start connection draining for graceful shutdown.", + " Enables draining mode where all HTTP/1 responses include\n" + " Connection: close to gracefully close client connections.\n" + " HTTP/2 connections receive a GOAWAY frame.", + 0, 0 +) + CLI_CMD(SERVER_START, "start", "start", diff --git a/include/tbl/params.h b/include/tbl/params.h index e66a653cb60..1f46a334db4 100644 --- a/include/tbl/params.h +++ b/include/tbl/params.h @@ -1085,6 +1085,24 @@ PARAM_SIMPLE( /* flags */ EXPERIMENTAL ) +PARAM_SIMPLE( + /* name */ drain_timeout, + /* type */ duration, + /* min */ "0.000", + /* max */ "300.000", + /* def */ "0.000", + /* units */ "seconds", + /* descr */ + "How long to wait for connections to drain when receiving a " + "shutdown signal (SIGTERM/SIGINT).\n\n" + "During this period, all HTTP/1 responses will include " + "'Connection: close' and HTTP/2 connections will receive " + "a GOAWAY frame, allowing clients to gracefully close " + "their connections.\n\n" + "Set to 0 to disable connection draining and shut down immediately.", + /* flags */ 0 +) + PARAM_SIMPLE( /* name */ transit_buffer, /* type */ bytes, diff --git a/include/tbl/sess_close.h b/include/tbl/sess_close.h index 009b5b20b03..94fb9a910a7 100644 --- a/include/tbl/sess_close.h +++ b/include/tbl/sess_close.h @@ -52,6 +52,7 @@ SESS_CLOSE(REQ_HTTP20, req_http20, 1, "HTTP2 not accepted") SESS_CLOSE(VCL_FAILURE, vcl_failure, 1, "VCL failure") SESS_CLOSE(RAPID_RESET, rapid_reset, 1, "HTTP2 rapid reset") SESS_CLOSE(BANKRUPT, bankrupt, 1, "HTTP2 credit bankruptcy") +SESS_CLOSE(DRAIN, drain, 0, "Connection draining") #undef SESS_CLOSE /*lint -restore */ diff --git a/lib/libvsc/VSC_main.vsc b/lib/libvsc/VSC_main.vsc index dc989dfb982..e59a9206af6 100644 --- a/lib/libvsc/VSC_main.vsc +++ b/lib/libvsc/VSC_main.vsc @@ -714,6 +714,13 @@ Number of times we ran out of space in workspace_backend. +.. varnish_vsc:: sc_drain + :level: diag + :oneliner: Session OK DRAIN + + Number of session closes with DRAIN (Connection draining for + graceful shutdown) + .. varnish_vsc:: ws_client_overflow :group: wrk :oneliner: workspace_client overflows