diff --git a/src/postgres/yb-extensions/yb_pg_metrics/yb_pg_metrics.c b/src/postgres/yb-extensions/yb_pg_metrics/yb_pg_metrics.c index 0fe4f616744b..a39fc449dd89 100644 --- a/src/postgres/yb-extensions/yb_pg_metrics/yb_pg_metrics.c +++ b/src/postgres/yb-extensions/yb_pg_metrics/yb_pg_metrics.c @@ -437,6 +437,12 @@ webserver_worker_main(Datum unused) MemoryContextSwitchTo(oldcontext); } + if (webserver) + { + DestroyWebserver(webserver); + webserver = NULL; + } + if (rc & WL_POSTMASTER_DEATH) proc_exit(1); diff --git a/src/yb/server/webserver.cc b/src/yb/server/webserver.cc index 7b8e229b2a82..4825763f4dc2 100644 --- a/src/yb/server/webserver.cc +++ b/src/yb/server/webserver.cc @@ -254,6 +254,9 @@ class Webserver::Impl { // Mutex guarding against concurrenct calls to Stop(). std::mutex stop_mutex_; + // Variable to notify handlers to stop serving requests. + std::atomic stop_initiated = false; + mutable std::mutex auto_flags_mutex_; // The AutoFlags that are associated with this particular server. In LTO builds we use the same // process for both yb-master and yb-tserver, so the process may have more AutoFlags than this @@ -448,11 +451,19 @@ Status Webserver::Impl::Start() { } void Webserver::Impl::Stop() { + // Indicate to the handlers that they can now stop serving requests. If any further signals are + // received to terminate the webserver, the handlers will no longer access non-static variables + // and will return immediately. + stop_initiated = true; + std::lock_guard lock_(stop_mutex_); if (context_ != nullptr) { + LOG(INFO) << "Stopping webserver on " << http_address_; sq_stop(context_); context_ = nullptr; } + + LOG(INFO) << "Webserver stopped"; } Status Webserver::Impl::GetInputHostPort(HostPort* hp) const { @@ -583,6 +594,13 @@ sq_callback_result_t Webserver::Impl::BeginRequestCallback(struct sq_connection* sq_callback_result_t Webserver::Impl::RunPathHandler(const PathHandler& handler, struct sq_connection* connection, struct sq_request_info* request_info) { + constexpr auto SERVICE_UNAVAILABLE_MSG = "HTTP/1.1 503 Service Unavailable\r\n"; + // If we're in the process of stopping, do not parse or route the request. Just return. + if (PREDICT_FALSE(stop_initiated)) { + sq_printf(connection, SERVICE_UNAVAILABLE_MSG); + return SQ_HANDLED_CLOSE_CONNECTION; + } + // Should we render with css styles? bool use_style = true; @@ -647,7 +665,7 @@ sq_callback_result_t Webserver::Impl::RunPathHandler(const PathHandler& handler, for (const PathHandlerCallback& callback_ : handler.callbacks()) { callback_(req, resp_ptr); if (resp_ptr->code == 503) { - sq_printf(connection, "HTTP/1.1 503 Service Unavailable\r\n"); + sq_printf(connection, SERVICE_UNAVAILABLE_MSG); return SQ_HANDLED_CLOSE_CONNECTION; } } diff --git a/src/yb/yql/pggate/webserver/pgsql_webserver_wrapper.cc b/src/yb/yql/pggate/webserver/pgsql_webserver_wrapper.cc index b70c511b9241..d7253c0a0ee2 100644 --- a/src/yb/yql/pggate/webserver/pgsql_webserver_wrapper.cc +++ b/src/yb/yql/pggate/webserver/pgsql_webserver_wrapper.cc @@ -624,6 +624,11 @@ YBCStatus StartWebserver(WebserverWrapper *webserver_wrapper) { return ToYBCStatus(WithMaskedYsqlSignals([webserver]() { return webserver->Start(); })); } +void DestroyWebserver(struct WebserverWrapper *webserver) { + Webserver *webserver_impl = reinterpret_cast(webserver); + delete webserver_impl; +} + void SetWebserverConfig( WebserverWrapper *webserver_wrapper, bool enable_access_logging, bool enable_tcmalloc_logging, int webserver_profiler_sample_freq_bytes) { diff --git a/src/yb/yql/pggate/webserver/pgsql_webserver_wrapper.h b/src/yb/yql/pggate/webserver/pgsql_webserver_wrapper.h index 4212e778d32f..8a96c929b839 100644 --- a/src/yb/yql/pggate/webserver/pgsql_webserver_wrapper.h +++ b/src/yb/yql/pggate/webserver/pgsql_webserver_wrapper.h @@ -99,6 +99,7 @@ typedef struct { } YbConnectionMetrics; struct WebserverWrapper *CreateWebserver(char *listen_addresses, int port); +void DestroyWebserver(struct WebserverWrapper *webserver); void RegisterMetrics(ybpgmEntry *tab, int num_entries, char *metric_node_name); void RegisterRpczEntries( postgresCallbacks *callbacks, int *num_backends_ptr, rpczEntry **rpczEntriesPointer,