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.
This commit is contained in:
Aurelien DARRAGON 2025-02-21 10:51:01 +01:00
parent c9d4192726
commit 9561b9fb69
2 changed files with 15 additions and 2 deletions

View File

@ -40,6 +40,7 @@ enum sink_type {
struct sink_forward_target { struct sink_forward_target {
struct server *srv; // used server struct server *srv; // used server
struct appctx *appctx; // appctx of current session 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 ofs; // ring buffer reader offset
size_t e_processed; // processed events size_t e_processed; // processed events
struct sink *sink; // the associated sink struct sink *sink; // the associated sink

View File

@ -654,6 +654,7 @@ static struct appctx *sink_forward_session_create(struct sink *sink, struct sink
goto out_close; goto out_close;
appctx->svcctx = (void *)sft; appctx->svcctx = (void *)sft;
appctx_wakeup(appctx); appctx_wakeup(appctx);
sft->last_conn = now_ms;
return appctx; return appctx;
/* Error unrolling */ /* 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 * assigment right away since the applet is not supposed to change
* during the session lifetime. By doing the assignment now we * during the session lifetime. By doing the assignment now we
* make sure to start the session exactly once. * 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) if (!sft->appctx) {
sft->appctx = sink_forward_session_create(sink, sft); 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); HA_SPIN_UNLOCK(SFT_LOCK, &sft->lock);
sft = sft->next; sft = sft->next;
} }