]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MINOR: mux-spop: Use a dedicated function to update the SPOP connection timeout
authorChristopher Faulet <cfaulet@haproxy.com>
Mon, 8 Jul 2024 17:17:34 +0000 (19:17 +0200)
committerChristopher Faulet <cfaulet@haproxy.com>
Fri, 12 Jul 2024 13:27:05 +0000 (15:27 +0200)
Force the SPOP servers to use the SPOE engine identifier as pool connection
name. This way, idle SPOP connections, once implemented, of different engine
but using the same backend will not be mixed up.

The related issue is #2502.

src/mux_spop.c

index 83616d9268e2a4d56f271cf04536550e62284ed6..5e6a73317509ec69ff49a12101adeea2fbd7eb6a 100644 (file)
@@ -827,13 +827,15 @@ static inline int spop_conn_is_dead(struct spop_conn *spop_conn)
 }
 
 /* update spop_conn timeout if needed */
-static __maybe_unused void spop_conn_update_timeout(struct spop_conn *spop_conn)
+static void spop_conn_update_timeout(struct spop_conn *spop_conn)
 {
-       TRACE_ENTER(SPOP_EV_SPOP_CONN_WAKE, spop_conn->conn);
+       int is_idle_conn = 0;
 
        if (!spop_conn->task)
                goto leave;
 
+       TRACE_ENTER(SPOP_EV_SPOP_CONN_WAKE, spop_conn->conn);
+
        if (spop_conn_may_expire(spop_conn)) {
                /* no more streams attached */
                if (br_data(spop_conn->mbuf)) {
@@ -846,6 +848,7 @@ static __maybe_unused void spop_conn_update_timeout(struct spop_conn *spop_conn)
                                int exp = tick_add_ifset(now_ms, spop_conn->shut_timeout);
 
                                spop_conn->task->expire = tick_first(spop_conn->task->expire, exp);
+                               is_idle_conn = 1;
                        }
 
                        /* if a timeout above was not set, fall back to the default one */
@@ -853,13 +856,41 @@ static __maybe_unused void spop_conn_update_timeout(struct spop_conn *spop_conn)
                                spop_conn->task->expire = tick_add_ifset(now_ms, spop_conn->timeout);
                }
 
-               // TODO: handle close_spread for now, there is no idle connection
+               if ((spop_conn->proxy->flags & (PR_FL_DISABLED|PR_FL_STOPPED)) &&
+                   is_idle_conn && tick_isset(global.close_spread_end)) {
+                       /* If a soft-stop is in progress and a close-spread-time
+                        * is set, we want to spread idle connection closing roughly
+                        * evenly across the defined window. This should only
+                        * act on idle frontend connections.
+                        * If the window end is already in the past, we wake the
+                        * timeout task up immediately so that it can be closed.
+                        */
+                       int remaining_window = tick_remain(now_ms, global.close_spread_end);
+                       if (remaining_window) {
+                               /* We don't need to reset the expire if it would
+                                * already happen before the close window end.
+                                */
+                               if (tick_isset(spop_conn->task->expire) &&
+                                   tick_is_le(global.close_spread_end, spop_conn->task->expire)) {
+                                       /* Set an expire value shorter than the current value
+                                        * because the close spread window end comes earlier.
+                                        */
+                                       spop_conn->task->expire = tick_add(now_ms, statistical_prng_range(remaining_window));
+                               }
+                       }
+                       else {
+                               /* We are past the soft close window end, wake the timeout
+                                * task up immediately.
+                                */
+                               task_wakeup(spop_conn->task, TASK_WOKEN_TIMER);
+                       }
+               }
        }
        else
                spop_conn->task->expire = TICK_ETERNITY;
        task_queue(spop_conn->task);
+       TRACE_LEAVE(SPOP_EV_SPOP_CONN_WAKE, spop_conn->conn, 0, 0, (size_t[]){spop_conn->task->expire});
  leave:
-       TRACE_LEAVE(SPOP_EV_SPOP_CONN_WAKE);
 }
 
 /********************************************************/
@@ -2495,11 +2526,7 @@ static int spop_process(struct spop_conn *spop_conn)
            (!br_data(spop_conn->mbuf) && ((spop_conn->flags & SPOP_CF_MUX_BLOCK_ANY) || LIST_ISEMPTY(&spop_conn->send_list))))
                spop_release_mbuf(spop_conn);
 
-       if (spop_conn->task) {
-               spop_conn->task->expire = tick_add(now_ms, (spop_conn->state == SPOP_CS_CLOSED ? spop_conn->shut_timeout : spop_conn->timeout));
-               task_queue(spop_conn->task);
-       }
-
+       spop_conn_update_timeout(spop_conn);
        spop_send(spop_conn);
        TRACE_LEAVE(SPOP_EV_SPOP_CONN_WAKE, conn);
        return 0;
@@ -2810,8 +2837,7 @@ static void spop_detach(struct sedesc *sd)
                spop_release(spop_conn);
        }
        else if (spop_conn->task) {
-               spop_conn->task->expire = tick_add(now_ms, (spop_conn->state == SPOP_CS_CLOSED ? spop_conn->shut_timeout : spop_conn->timeout));
-               task_queue(spop_conn->task);
+               spop_conn_update_timeout(spop_conn);
                TRACE_DEVEL("leaving, refreshing connection's timeout", SPOP_EV_STRM_END, spop_conn->conn);
        }
        else