From cf3173d92b178bd9bbcb22002001f0cff8e5f275 Mon Sep 17 00:00:00 2001 From: Willy Tarreau Date: Mon, 30 Mar 2026 16:19:51 +0200 Subject: [PATCH] MINOR: stconn: flag the stream endpoint descriptor when the app has started In order to improve our ability to distinguish operations that had already started from others under high loads, it would be nice to know if an application layer (stream) has started to work with an endpoint or not. The use case typically is a frontend mux instantiating a stream to instantly cancel it. Currently this info will take some time to be detected and processed if the applcation's task takes time to wake up. By flagging the sedesc with SE_FL_APP_STARTED the first time a the app layer starts, the lower layers can know whether they're cancelling a stream that has started to work or not, and act accordingly. For now this is done unconditionally on the backend, and performed early in the only two app layers that can be reached by a frontend: process_stream() and process_hstream() (for haterm). --- include/haproxy/stconn-t.h | 8 +++++--- src/haterm.c | 4 ++++ src/stconn.c | 5 +++++ src/stream.c | 4 ++++ 4 files changed, 18 insertions(+), 3 deletions(-) diff --git a/include/haproxy/stconn-t.h b/include/haproxy/stconn-t.h index 02cf9840f..5b6d440a6 100644 --- a/include/haproxy/stconn-t.h +++ b/include/haproxy/stconn-t.h @@ -73,7 +73,9 @@ enum se_flags { SE_FL_DETACHED = 0x00000010, /* The endpoint is detached (no mux/no applet) */ SE_FL_ORPHAN = 0x00000020, /* The endpoint is orphan (no stream connector) */ - /* unused: 0x00000040 .. 0x00000080 */ + SE_FL_APP_STARTED= 0x00000040, /* the application layer has really started */ + + /* unused: 0x00000080 */ SE_FL_SHRD = 0x00000100, /* read shut, draining extra data */ SE_FL_SHRR = 0x00000200, /* read shut, resetting extra data */ @@ -135,12 +137,12 @@ static forceinline char *se_show_flags(char *buf, size_t len, const char *delim, _(0); /* flags */ _(SE_FL_T_MUX, _(SE_FL_T_APPLET, _(SE_FL_DETACHED, _(SE_FL_ORPHAN, - _(SE_FL_SHRD, _(SE_FL_SHRR, _(SE_FL_SHWN, _(SE_FL_SHWS, + _(SE_FL_APP_STARTED, _(SE_FL_SHRD, _(SE_FL_SHRR, _(SE_FL_SHWN, _(SE_FL_SHWS, _(SE_FL_NOT_FIRST, _(SE_FL_WEBSOCKET, _(SE_FL_EOI, _(SE_FL_EOS, _(SE_FL_ERROR, _(SE_FL_ERR_PENDING, _(SE_FL_RCV_MORE, _(SE_FL_WANT_ROOM, _(SE_FL_EXP_NO_DATA, _(SE_FL_MAY_FASTFWD_PROD, _(SE_FL_MAY_FASTFWD_CONS, _(SE_FL_WAIT_FOR_HS, _(SE_FL_KILL_CONN, _(SE_FL_WAIT_DATA, - _(SE_FL_WONT_CONSUME, _(SE_FL_HAVE_NO_DATA, _(SE_FL_APPLET_NEED_CONN))))))))))))))))))))))))); + _(SE_FL_WONT_CONSUME, _(SE_FL_HAVE_NO_DATA, _(SE_FL_APPLET_NEED_CONN)))))))))))))))))))))))))); /* epilogue */ _(~0U); return buf; diff --git a/src/haterm.c b/src/haterm.c index c2e112b29..2891e12b7 100644 --- a/src/haterm.c +++ b/src/haterm.c @@ -787,6 +787,10 @@ static struct task *process_hstream(struct task *t, void *context, unsigned int struct htx_sl *sl = http_get_stline(htx); struct http_hdr_ctx expect, clength; + /* we're starting to work with this endpoint, let's flag it */ + if (unlikely(!sc_ep_test(hs->sc, SE_FL_APP_STARTED))) + sc_ep_set(hs->sc, SE_FL_APP_STARTED); + if (sl->flags & HTX_SL_F_VER_11) hs->ka = 5; diff --git a/src/stconn.c b/src/stconn.c index e20c24529..6f7f3be60 100644 --- a/src/stconn.c +++ b/src/stconn.c @@ -210,6 +210,10 @@ struct stconn *sc_new_from_strm(struct stream *strm, unsigned int flags) if (unlikely(!sc)) return NULL; sc->flags |= flags; + + if (flags & SC_FL_ISBACK) + sc_ep_set(sc, SE_FL_APP_STARTED); + sc_ep_set(sc, SE_FL_DETACHED); sc->app = &strm->obj_type; return sc; @@ -227,6 +231,7 @@ struct stconn *sc_new_from_check(struct check *check) if (unlikely(!sc)) return NULL; sc->flags = SC_FL_ISBACK; + sc_ep_set(sc, SE_FL_APP_STARTED); sc_ep_set(sc, SE_FL_DETACHED); sc->app = &check->obj_type; return sc; diff --git a/src/stream.c b/src/stream.c index 3ba3f5888..40f9f75ae 100644 --- a/src/stream.c +++ b/src/stream.c @@ -1894,6 +1894,10 @@ struct task *process_stream(struct task *t, void *context, unsigned int state) SF_ERR_KILLED)); } + /* we're starting to work with this endpoint, let's flag it */ + if (unlikely(!sc_ep_test(scf, SE_FL_APP_STARTED))) + sc_ep_set(scf, SE_FL_APP_STARTED); + /* First, attempt to receive pending data from I/O layers */ sc_sync_recv(scf); sc_sync_recv(scb);