From: Amaury Denoyelle Date: Thu, 17 Sep 2026 13:48:20 +0000 (+0200) Subject: MINOR: proxy: define purge task and purge servers list X-Git-Tag: v3.5-dev9~18 X-Git-Url: https://git.kaiwu.me/?a=commitdiff_plain;h=120834d7059671bbc3c1899d016e3f1cc713839b;p=haproxy.git MINOR: proxy: define purge task and purge servers list Add two new members in proxy type. First, a 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, 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. --- diff --git a/include/haproxy/proxy-t.h b/include/haproxy/proxy-t.h index f9db0482b..d45d8731d 100644 --- a/include/haproxy/proxy-t.h +++ b/include/haproxy/proxy-t.h @@ -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 */ diff --git a/src/proxy.c b/src/proxy.c index 9c4fb5d0c..14ccd1edc 100644 --- a/src/proxy.c +++ b/src/proxy.c @@ -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; }