]> git.kaiwu.me - haproxy.git/commitdiff
MINOR: proxy: yield during servers purge
authorAmaury Denoyelle <adenoyelle@haproxy.com>
Thu, 1 Oct 2026 14:40:58 +0000 (16:40 +0200)
committerAmaury Denoyelle <adenoyelle@haproxy.com>
Wed, 14 Oct 2026 09:33:40 +0000 (11:33 +0200)
Function proxy_purge_servers() loops through server purge list and tries
to remove them. This is executed under thread isolation for the whole
function duration.

To prevent blocking for too long, yield after 50 servers deleted. The
purge task is immediately requeued but this gives an opportunity for the
other threads to achieve some work.

For now, a static value is applied as the yield limit. It may be useful
to render it configurable if users want to prioritize traffic even more.

src/proxy.c

index 0c8da9d0a0c9487df5202e02246128c7d02d15dc..ad87f90fa4cf6fb1e64468630f707c600fc81a61 100644 (file)
@@ -510,13 +510,25 @@ void proxy_drop(struct proxy *p)
        ha_free(&p);
 }
 
-/* Try to delete servers flagged for purge in <px> backend. */
-static int proxy_purge_servers(struct proxy *px)
+/* Try to delete servers flagged for purge in <px> backend.
+ *
+ * This function must only runs in thread isolation. To avoid too long run, at
+ * most <max_srv_delete> instances are removed until the function returns, so
+ * that the caller can yield.
+ *
+ * Returns 0 if either all scheduled servers are deleted or iteration stopped
+ * on a server is still active. A non zero is used when <max_srv_delete> count
+ * of servers were removed and purge list is not yet empty.
+ */
+static int proxy_purge_servers(struct proxy *px, int max_srv_delete)
 {
        struct server *srv;
        int ret;
 
        while (!LIST_ISEMPTY(&px->servers_purge)) {
+               if (!max_srv_delete)
+                       break;
+
                srv = LIST_NEXT(&px->servers_purge, struct server *, el_alt);
                if (!(srv->flags & SRV_F_TO_PURGE)) {
                        LIST_DEL_INIT(&srv->el_alt);
@@ -533,7 +545,7 @@ static int proxy_purge_servers(struct proxy *px)
                        ha_notice("Server '%s/%s' purged.\n", px->id, srv->id);
                        srv_unregister(srv);
                        srv_drop(srv);
-                       /* TODO yield after nth deletion performed in a row */
+                       --max_srv_delete;
                }
                else {
                        /* Interrupt work on first server not yet removable. */
@@ -541,7 +553,7 @@ static int proxy_purge_servers(struct proxy *px)
                }
        }
 
-       return 0;
+       return !(LIST_ISEMPTY(&px->servers_purge) || max_srv_delete);
 }
 
 /* Proxy purge task handler, only used by user configured backend instances.
@@ -551,6 +563,8 @@ static int proxy_purge_servers(struct proxy *px)
 struct task *proxy_process_purge(struct task *t, void *context, unsigned int state)
 {
        struct proxy *px = context;
+       /* constant for max number of server delete before yield */
+       const int max_srv_delete = 50;
 
        /* Must not dereference <px> before entering thread isolation and
         * checking task state, as proxy_drop() performed outside isolation
@@ -566,8 +580,12 @@ struct task *proxy_process_purge(struct task *t, void *context, unsigned int sta
                goto requeue;
        }
 
-       if (!LIST_ISEMPTY(&px->servers_purge))
-               proxy_purge_servers(px);
+       if (!LIST_ISEMPTY(&px->servers_purge)) {
+               if (proxy_purge_servers(px, max_srv_delete)) {
+                       task_wakeup(px->purge_task, TASK_WOKEN_OTHER);
+                       goto requeue;
+               }
+       }
 
        /* Set next task execution or cancel it if no more work to do. */
        if (!LIST_ISEMPTY(&px->servers_purge))