]> git.kaiwu.me - haproxy.git/commitdiff
MINOR: proxy: define purge task and purge servers list
authorAmaury Denoyelle <adenoyelle@haproxy.com>
Thu, 17 Sep 2026 13:48:20 +0000 (15:48 +0200)
committerAmaury Denoyelle <adenoyelle@haproxy.com>
Wed, 14 Oct 2026 09:21:29 +0000 (11:21 +0200)
Add two new members in proxy type.

First, a task <purge_task> is added. It will be used as an internal task
to cleanup proxy related resources, i.e. its servers and the proxy
itself. The task is allocated only for non internal backend instances.
Handler proxy_process_purge() runs in thread isolation to prevent any
race conditions. This task may run on any thread, thus task_kill() is
used on proxy deinit to ensure runtime backend deletion is still safe.

Second, <servers_purge> is a new list member in proxy. This will contain
any server targeted for a background deletion. Purge task handler will
run itself every second until the list is empty.

For now, task handler is mostly empty and servers purge list is not
used. This will be extended when purge CLI commands for servers and
backends will be implemented.

include/haproxy/proxy-t.h
src/proxy.c

index f9db0482be51983215d0d25e9909e2fed3bc5295..d45d8731d9a62780d9b59591c2387f78b2d6b5cc 100644 (file)
@@ -370,6 +370,7 @@ struct proxy {
        struct list quic_init_rules;            /* quic-initial rules */
 #endif
        struct list servers;            /* servers present in current backend */
+       struct list servers_purge;              /* servers scheduled for purge */
        struct server *defsrv;                  /* default server configuration */
        struct ceb_root *defsrv_by_name;        /* named default servers */
        struct lbprm lbprm;                     /* load-balancing parameters */
@@ -452,6 +453,7 @@ struct proxy {
        struct stktable *table;                 /* table for storing sticking streams */
 
        struct task *task;                      /* the associated task, mandatory to manage rate limiting, stopping and resource shortage, NULL if disabled */
+       struct task *purge_task;                /* backend only task - used to delete purgeable servers or the backend itself */
        struct tcpcheck tcpcheck;               /* tcp-check to use to perform a health-check */
        char *check_command;                    /* Command to use for external agent checks */
        char *check_path;                       /* PATH environment to use for external agent checks */
index 9c4fb5d0ced77b7558317ed77b135ca466d14658..14ccd1edc8bb1e8619d1af8d84d6cf78cc24584f 100644 (file)
@@ -475,6 +475,8 @@ void deinit_proxy(struct proxy *p)
        free(p->desc);
 
        task_destroy(p->task);
+       if (p->purge_task)
+               task_kill(p->purge_task);
 
        pool_destroy(p->req_cap_pool);
        pool_destroy(p->rsp_cap_pool);
@@ -508,6 +510,33 @@ void proxy_drop(struct proxy *p)
        ha_free(&p);
 }
 
+/* Proxy purge task handler, only used by user configured backend instances.
+ * Its objective is to remove any servers flagged with purge or the backend
+ * instance itself.
+ */
+struct task *proxy_process_purge(struct task *t, void *context, unsigned int state)
+{
+       struct proxy *px = context;
+
+       thread_isolate_full();
+
+       if (t->state & TASK_KILLED) {
+               /* Task killed indicate that the proxy instance has been freed.
+                * Mandatory check after entering thread isolation.
+                */
+               goto requeue;
+       }
+
+       if (!LIST_ISEMPTY(&px->servers_purge))
+               t->expire = tick_add(now_ms, MS_TO_TICKS(1000));
+       else
+               t->expire = TICK_ETERNITY;
+
+ requeue:
+       thread_release();
+       return t;
+}
+
 /*
  * This function returns a string containing a name describing capabilities to
  * report comprehensible error messages. Specifically, it will return the words
@@ -1635,6 +1664,7 @@ void init_new_proxy(struct proxy *p)
        p->obj_type = OBJ_TYPE_PROXY;
        LIST_INIT(&p->global_list);
        LIST_INIT(&p->servers);
+       LIST_INIT(&p->servers_purge);
        LIST_INIT(&p->el);
        LIST_INIT(&p->acl);
        LIST_INIT(&p->http_req_rules);
@@ -3295,6 +3325,21 @@ int setup_new_proxy(struct proxy *px, const char *name, unsigned int cap, char *
        if (name && name[0] != '\0' && !(cap & PR_CAP_INT))
                proxy_store_name(px);
 
+       /* Allocate purge task for proxies with backend capabilities - restricted
+        * to user visible instances, i.e. listen/backend from the config file
+        * or added at runtime via CLI.
+        */
+       if ((cap & (PR_CAP_BE|PR_CAP_LB)) == (PR_CAP_BE|PR_CAP_LB)) {
+               px->purge_task = task_new_anywhere();
+               if (!px->purge_task) {
+                       memprintf(errmsg, "out of memory while allocating purge task");
+                       goto fail;
+               }
+               px->purge_task->context = px;
+               px->purge_task->process = proxy_process_purge;
+               px->purge_task->expire = TICK_ETERNITY;
+       }
+
        if (!(cap & PR_CAP_DEF)) {
                LIST_APPEND(&all_proxies, &px->global_list);
                event_hdl_sub_list_init(&px->e_subs);
@@ -3311,6 +3356,11 @@ int setup_new_proxy(struct proxy *px, const char *name, unsigned int cap, char *
        counters_fe_shared_drop(&px->fe_counters.shared);
        counters_be_shared_drop(&px->be_counters.shared);
 
+       if (px->purge_task) {
+               task_destroy(px->purge_task);
+               px->purge_task = NULL;
+       }
+
        return 0;
 }