BUG/MEDIUM: spoe: Don't wakeup idle applets in loop during stopping
authorChristopher Faulet <cfaulet@haproxy.com>
Wed, 19 Feb 2025 10:39:59 +0000 (11:39 +0100)
committerChristopher Faulet <cfaulet@haproxy.com>
Wed, 19 Feb 2025 12:08:33 +0000 (13:08 +0100)
When HAproxy is stopping, idle applets are systematically woken up, to have a
change to close them. This was performed to properly handle the applets switched
to idle state after processing in synchronous mode. However, there was an issue
in async and pipelining modes. Applets remained idles while they had some free
slots to process messages. So these applets were not closed immediately and were
woken up in loop.

Now, we also take care to check that idle applets are not processing messages to
wake them up. The test is also moved after a processing attempt because it is
the right place to do so. There is no reason to perform this test systematically
at the end of the I/O handler.

This patch should be backported to all stable versions.

src/flt_spoe.c

index 7d8c89c..943e27b 100644 (file)
@@ -1969,8 +1969,11 @@ spoe_handle_appctx(struct appctx *appctx)
                case SPOE_APPCTX_ST_PROCESSING:
                case SPOE_APPCTX_ST_SENDING_FRAG_NOTIFY:
                case SPOE_APPCTX_ST_WAITING_SYNC_ACK:
-                       if (spoe_handle_processing_appctx(appctx))
+                       if (spoe_handle_processing_appctx(appctx)) {
+                               if (stopping && appctx->st0 == SPOE_APPCTX_ST_IDLE && !SPOE_APPCTX(appctx)->cur_fpa)
+                                       task_wakeup(SPOE_APPCTX(appctx)->task, TASK_WOKEN_MSG);
                                goto out;
+                       }
                        goto switchstate;
 
                case SPOE_APPCTX_ST_DISCONNECT:
@@ -1998,9 +2001,7 @@ spoe_handle_appctx(struct appctx *appctx)
                        return;
        }
   out:
-       if (stopping && appctx->st0 == SPOE_APPCTX_ST_IDLE)
-               task_wakeup(SPOE_APPCTX(appctx)->task, TASK_WOKEN_MSG);
-       else if (SPOE_APPCTX(appctx)->task->expire != TICK_ETERNITY)
+       if (SPOE_APPCTX(appctx)->task->expire != TICK_ETERNITY)
                task_queue(SPOE_APPCTX(appctx)->task);
 }