]> git.ipfire.org Git - thirdparty/apache/httpd.git/commitdiff
mod_proxy_hcheck: Fix healthcheck disabled due to child restart while updating
authorYann Ylavic <ylavic@apache.org>
Tue, 25 Nov 2025 11:39:28 +0000 (11:39 +0000)
committerYann Ylavic <ylavic@apache.org>
Tue, 25 Nov 2025 11:39:28 +0000 (11:39 +0000)
When a child gets restarted while the healthcheck watchdog running for a
worker, the healcheck will be disabled for that worker indefinitively because
its ->updated time remains zero. Fix all zero ->updated time at startup.

* mod_proxy_hcheck.c(hc_watchdog_callback):
  Have AP_WATCHDOG_STATE_STARTING set the ->updated time of all the workers to
  "now" (if zero).
  Move up scoped variables common to AP_WATCHDOG_STATE_{STARTING,RUNNING}
  loops.

Reported by: Lubos Uhliarik <luhliari redhat.com>

git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1929972 13f79535-47bb-0310-9956-ffa450edef68

modules/proxy/mod_proxy_hcheck.c

index 568603594d224794e3f0fc30065a1b591a7a41b3..92e1bced286d3b104581f9122503e8a99553d399 100644 (file)
@@ -989,12 +989,32 @@ static apr_status_t hc_watchdog_callback(int state, void *data,
     sctx_t *ctx = (sctx_t *)data;
     server_rec *s = ctx->s;
     proxy_server_conf *conf;
+    proxy_worker **workers;
+    proxy_worker *worker;
+    apr_time_t now;
+    int i, n;
+
+    conf = ap_get_module_config(s->module_config, &proxy_module);
 
     switch (state) {
         case AP_WATCHDOG_STATE_STARTING:
             ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(03258)
                          "%s watchdog started.",
                          HCHECK_WATHCHDOG_NAME);
+            /* If a child exits while running an hcheck the ->updated time will
+             * be zero, preventing further hcheck for the worker.
+             */
+            now = apr_time_now();
+            balancer = (proxy_balancer *)conf->balancers->elts;
+            for (i = 0; i < conf->balancers->nelts; i++, balancer++) {
+                workers = (proxy_worker **)balancer->workers->elts;
+                for (n = 0; n < balancer->workers->nelts; n++, workers++) {
+                    worker = *workers;
+                    if (worker->s->updated == 0) {
+                        worker->s->updated = now;
+                    }
+                }
+            }
 #if HC_USE_THREADS
             if (tpsize && hctp == NULL) {
                 rv =  apr_thread_pool_create(&hctp, tpsize,
@@ -1020,29 +1040,28 @@ static apr_status_t hc_watchdog_callback(int state, void *data,
 
         case AP_WATCHDOG_STATE_RUNNING:
             /* loop thru all workers */
-            if (s) {
-                int i;
-                conf = (proxy_server_conf *) ap_get_module_config(s->module_config, &proxy_module);
+            {
                 balancer = (proxy_balancer *)conf->balancers->elts;
-                ctx->s = s;
                 for (i = 0; i < conf->balancers->nelts; i++, balancer++) {
-                    int n;
-                    apr_time_t now;
-                    proxy_worker **workers;
-                    proxy_worker *worker;
                     /* Have any new balancers or workers been added dynamically? */
                     ap_proxy_sync_balancer(balancer, s, conf);
-                    workers = (proxy_worker **)balancer->workers->elts;
+
                     now = apr_time_now();
-                    for (n = 0; n < balancer->workers->nelts; n++) {
+                    workers = (proxy_worker **)balancer->workers->elts;
+                    for (n = 0; n < balancer->workers->nelts; n++, workers++) {
                         worker = *workers;
                         if (!PROXY_WORKER_IS(worker, PROXY_WORKER_STOPPED) &&
                             (worker->s->method != NONE) &&
-                            (worker->s->updated != 0) &&
-                            (now > worker->s->updated + worker->s->interval)) {
+                            (now > worker->s->updated + worker->s->interval) &&
+                            (worker->s->updated != 0)) {
                             baton_t *baton;
                             apr_pool_t *ptemp;
 
+                            /* Zero to prevent concurrent checks for the same worker,
+                             * should a check take longer than the watchdog interval.
+                             */
+                            worker->s->updated = 0;
+
                             ap_log_error(APLOG_MARK, APLOG_TRACE3, 0, s,
                                          "Checking %s worker: %s  [%d] (%pp)", balancer->s->name,
                                          worker->s->name, worker->s->method, worker);
@@ -1060,7 +1079,7 @@ static apr_status_t hc_watchdog_callback(int state, void *data,
                                 apr_pool_destroy(ptemp);
                                 return rv;
                             }
-                            worker->s->updated = 0;
+
 #if HC_USE_THREADS
                             if (hctp) {
                                 apr_thread_pool_push(hctp, hc_check, (void *)baton,
@@ -1074,7 +1093,6 @@ static apr_status_t hc_watchdog_callback(int state, void *data,
                                 hc_check(NULL, baton);
                             }
                         }
-                        workers++;
                     }
                 }
             }