BUG/MEDIUM: resolvers: Properly stop server resolutions on soft-stop

When HAproxy is stopping, the DNS resolutions must be stopped, except those
triggered from a "do-resolve" action. To do so, the resolutions themselves
cannot be destroyed, the current design is too complex. However, it is
possible to mute the resolvers tasks. The same is already performed with the
health-checks. On soft-stop, the tasks are still running periodically but
nothing if performed.

For the resolvers, when the process is stopping, before running a
resolution, we check all the requesters attached to this resolution. If t
least a request is a stream or if there is a requester attached to a running
proxy, a new resolution is triggered. Otherwise, we ignored the
resolution. It will be evaluated again on the next wakeup. This way,
"do-resolv" action are still working during soft-stop but other resoluation
are stopped.

Of course, it may be see as a feature and not a bug because it was never
performed. But it is in fact not expected at all to still performing
resolutions when HAProxy is stopping. In addution, a proxy option will be
added to change this behavior.

This patch partially fixes the issue #1874. It could be backported to 2.7
and maybe to 2.6. But no further.

(cherry picked from commit 52ec6f14c4cbfe23cbe3bf6ef55af84ba17047de)
Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>
(cherry picked from commit 058782b3f28d4ea6543f24d4996f97410f4e9f49)
Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>
This commit is contained in:
Christopher Faulet 2023-03-14 14:41:55 +01:00
parent 883f35da4b
commit b3c4d38aa8

View File

@ -2394,6 +2394,48 @@ static struct task *process_resolvers(struct task *t, void *context, unsigned in
/* Handle all resolutions in the wait list */
list_for_each_entry_safe(res, resback, &resolvers->resolutions.wait, list) {
if (unlikely(stopping)) {
/* If haproxy is stopping, check if the resolution to know if it must be run or not.
* If at least a requester is a stream (because of a do-resolv action) or if there
* is a requester attached to a running proxy, the resolution is performed.
* Otherwise, it is skipped for now.
*/
struct resolv_requester *req;
int must_run = 0;
list_for_each_entry(req, &res->requesters, list) {
struct proxy *px = NULL;
switch (obj_type(req->owner)) {
case OBJ_TYPE_SERVER:
px = __objt_server(req->owner)->proxy;
break;
case OBJ_TYPE_SRVRQ:
px = __objt_resolv_srvrq(req->owner)->proxy;
break;
case OBJ_TYPE_STREAM:
/* Always perform the resolution */
must_run = 1;
break;
default:
break;
}
/* Perform the resolution if the proxy is not stopped or disabled */
if (px && !(px->flags & (PR_FL_DISABLED|PR_FL_STOPPED)))
must_run = 1;
if (must_run)
break;
}
if (!must_run) {
/* Skip the reolsution. reset it and wait for the next wakeup */
resolv_reset_resolution(res);
continue;
}
}
if (LIST_ISEMPTY(&res->requesters)) {
abort_resolution(res);
continue;