From 9561b9fb6964af325a10e7128b563114f144a3cb Mon Sep 17 00:00:00 2001 From: Aurelien DARRAGON Date: Fri, 21 Feb 2025 10:51:01 +0100 Subject: [PATCH] BUG/MINOR: sink: add tempo between 2 connection attempts for sft servers When the connection for sink_forward_{oc}_applet fails or a previous one is destroyed, the sft->appctx is instantly released. However process_sink_forward_task(), which may run at any time, iterates over all known sfts and tries to create sessions for orphan ones. It means that instantly after sft->appctx is destroyed, a new one will be created, thus a new connection attempt will be made. It can be an issue with tcp log-servers or sink servers, because if the server is unavailable, process_sink_forward() will keep looping without any temporisation until the applet survives (ie: connection succeeds), which results in unexpected CPU usage on the threads responsible for that task. Instead, we add a tempo logic so that a delay of 1second is applied between two retries. Of course the initial attempt is not delayed. This could be backported to all stable versions. --- include/haproxy/sink-t.h | 1 + src/sink.c | 16 ++++++++++++++-- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/include/haproxy/sink-t.h b/include/haproxy/sink-t.h index f72a4e12a..a9db336f1 100644 --- a/include/haproxy/sink-t.h +++ b/include/haproxy/sink-t.h @@ -40,6 +40,7 @@ enum sink_type { struct sink_forward_target { struct server *srv; // used server struct appctx *appctx; // appctx of current session + uint last_conn; // copy of now_ms for last session establishment attempt size_t ofs; // ring buffer reader offset size_t e_processed; // processed events struct sink *sink; // the associated sink diff --git a/src/sink.c b/src/sink.c index 25d7a2fee..a12fe51d4 100644 --- a/src/sink.c +++ b/src/sink.c @@ -654,6 +654,7 @@ static struct appctx *sink_forward_session_create(struct sink *sink, struct sink goto out_close; appctx->svcctx = (void *)sft; appctx_wakeup(appctx); + sft->last_conn = now_ms; return appctx; /* Error unrolling */ @@ -678,9 +679,20 @@ static struct task *process_sink_forward(struct task * task, void *context, unsi * assigment right away since the applet is not supposed to change * during the session lifetime. By doing the assignment now we * make sure to start the session exactly once. + * + * We enforce a tempo to ensure we don't perform more than 1 session + * establishment attempt per second. */ - if (!sft->appctx) - sft->appctx = sink_forward_session_create(sink, sft); + if (!sft->appctx) { + uint tempo = sft->last_conn + MS_TO_TICKS(1000); + + if (sft->last_conn == TICK_ETERNITY || tick_is_expired(tempo, now_ms)) + sft->appctx = sink_forward_session_create(sink, sft); + else if (task->expire == TICK_ETERNITY) + task->expire = tempo; + else + task->expire = tick_first(task->expire, tempo); + } HA_SPIN_UNLOCK(SFT_LOCK, &sft->lock); sft = sft->next; }