]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
BUG/MEDIUM: spoe: Create a SPOE applet if necessary when the last one is released
authorChristopher Faulet <cfaulet@haproxy.com>
Mon, 2 Aug 2021 15:53:56 +0000 (17:53 +0200)
committerChristopher Faulet <cfaulet@haproxy.com>
Thu, 5 Aug 2021 08:07:43 +0000 (10:07 +0200)
On a thread, when the last SPOE applet is released, if there are still
pending streams, a new one is created. Of course, HAproxy must not be
stopping. It is important to start a new applet in this case to not abort
in-progress jobs, especially when a maxconn is set. Because applets may be
closed to be fair with connections waiting for a free slot.

This patch should partely fix the issue #1340. It depends on the commit
"MINOR: spoe: Create a SPOE applet if necessary when the last one on a
thread is closed". Both must be backported as far as 2.0.

src/flt_spoe.c

index 90aed12a94993d168fee1c199ddf6fcb68f42ae2..931014665561994e5cd609d67b4e6031bacbf298 100644 (file)
@@ -103,6 +103,7 @@ struct flt_ops spoe_ops;
 static int  spoe_queue_context(struct spoe_context *ctx);
 static int  spoe_acquire_buffer(struct buffer *buf, struct buffer_wait *buffer_wait);
 static void spoe_release_buffer(struct buffer *buf, struct buffer_wait *buffer_wait);
+static struct appctx *spoe_create_appctx(struct spoe_config *conf);
 
 /********************************************************************
  * helper functions/globals
@@ -1287,27 +1288,37 @@ spoe_release_appctx(struct appctx *appctx)
                }
                goto end;
        }
+       else {
+               /* It is the last running applet and the sending and waiting
+                * queues are not empty. Try to start a new one if HAproxy is
+                * not stopping.
+                */
+               if (!stopping &&
+                   (!LIST_ISEMPTY(&agent->rt[tid].sending_queue) || !LIST_ISEMPTY(&agent->rt[tid].waiting_queue)) &&
+                   spoe_create_appctx(agent->spoe_conf))
+                       goto end;
 
-       /* If this was the last running applet, notify all waiting streams */
-       list_for_each_entry_safe(ctx, back, &agent->rt[tid].sending_queue, list) {
-               LIST_DELETE(&ctx->list);
-               LIST_INIT(&ctx->list);
-               _HA_ATOMIC_DEC(&agent->counters.nb_sending);
-               spoe_update_stat_time(&ctx->stats.tv_queue, &ctx->stats.t_queue);
-               ctx->spoe_appctx = NULL;
-               ctx->state = SPOE_CTX_ST_ERROR;
-               ctx->status_code = (spoe_appctx->status_code + 0x100);
-               task_wakeup(ctx->strm->task, TASK_WOKEN_MSG);
-       }
-       list_for_each_entry_safe(ctx, back, &agent->rt[tid].waiting_queue, list) {
-               LIST_DELETE(&ctx->list);
-               LIST_INIT(&ctx->list);
-               _HA_ATOMIC_DEC(&agent->counters.nb_waiting);
-               spoe_update_stat_time(&ctx->stats.tv_wait, &ctx->stats.t_waiting);
-               ctx->spoe_appctx = NULL;
-               ctx->state = SPOE_CTX_ST_ERROR;
-               ctx->status_code = (spoe_appctx->status_code + 0x100);
-               task_wakeup(ctx->strm->task, TASK_WOKEN_MSG);
+               /* otherwise, notify all waiting streams */
+               list_for_each_entry_safe(ctx, back, &agent->rt[tid].sending_queue, list) {
+                       LIST_DELETE(&ctx->list);
+                       LIST_INIT(&ctx->list);
+                       _HA_ATOMIC_DEC(&agent->counters.nb_sending);
+                       spoe_update_stat_time(&ctx->stats.tv_queue, &ctx->stats.t_queue);
+                       ctx->spoe_appctx = NULL;
+                       ctx->state = SPOE_CTX_ST_ERROR;
+                       ctx->status_code = (spoe_appctx->status_code + 0x100);
+                       task_wakeup(ctx->strm->task, TASK_WOKEN_MSG);
+               }
+               list_for_each_entry_safe(ctx, back, &agent->rt[tid].waiting_queue, list) {
+                       LIST_DELETE(&ctx->list);
+                       LIST_INIT(&ctx->list);
+                       _HA_ATOMIC_DEC(&agent->counters.nb_waiting);
+                       spoe_update_stat_time(&ctx->stats.tv_wait, &ctx->stats.t_waiting);
+                       ctx->spoe_appctx = NULL;
+                       ctx->state = SPOE_CTX_ST_ERROR;
+                       ctx->status_code = (spoe_appctx->status_code + 0x100);
+                       task_wakeup(ctx->strm->task, TASK_WOKEN_MSG);
+               }
        }
 
   end: