Skip to content

fix(upstream): keep last resolved address on transient DNS failure - #13903

Open
janiussyafiq wants to merge 2 commits into
apache:masterfrom
janiussyafiq:fix/healthcheck-dns-node-churn
Open

fix(upstream): keep last resolved address on transient DNS failure#13903
janiussyafiq wants to merge 2 commits into
apache:masterfrom
janiussyafiq:fix/healthcheck-dns-node-churn

Conversation

@janiussyafiq

Copy link
Copy Markdown
Contributor

Description

When an upstream uses a domain name in nodes, a transient DNS failure (timeout, SERVFAIL) during periodic re-resolution dropped the node from the resolved node list.
When DNS recovered moments later, the node was re-added.
That drop/re-add changes the node list, which rebuilds the health checker, and a re-added target always starts as healthy.
As a result, a node that active checks had correctly marked unhealthy received traffic again without passing any recovery probe, and workers could disagree about its state because each of them resolves independently.

The DNS failure says nothing about the backend's health, so it should not destroy the health checker's state.

This PR:

  • returns the DNS rcode from core.dns.client.resolve() / core.resolver.parse_domain() as a third value, so callers can tell an authoritative NXDOMAIN answer apart from a query that could not be completed at all
  • on a failed query that is not NXDOMAIN, keeps the node at its last resolved address instead of dropping it: the node list stays stable, the checker target survives, and the unhealthy state is preserved while probes keep running
  • on an authoritative NXDOMAIN, still removes the node, since the server positively stated the name no longer exists
  • makes sort_by_key_host tie-break on port, so two nodes sharing one IP cannot sort unstably and report a phantom node change

Verified against an end-to-end reproduction (3-node upstream, one node failing its health endpoint, DNS server blipped for 8 seconds): without the fix the unhealthy node returns to rotation on all workers after the blip; with the fix it receives no traffic and stays unhealthy.

Which issue(s) this PR fixes:

Fixes #13888

Checklist

  • I have explained the need for this PR and the problem it solves
  • I have explained the changes or the new features added to this PR
  • I have added tests corresponding to this change
  • I have updated the documentation to reflect this change
  • I have verified that this change is backward compatible (If not, please discuss on the APISIX mailing list first)

A transient DNS failure (timeout, SERVFAIL) dropped the domain node from
the upstream node list. The node churn rebuilt the health checker, and the
re-added target starts as healthy, so a node that was correctly marked
unhealthy received traffic again without passing any recovery probe.

Keep the last resolved address when the query cannot be completed, so the
node list stays stable and health state survives. An authoritative
NXDOMAIN answer still removes the node.
httpc:request_uri can return nil, err; dereferencing res.status would
raise instead of reporting the HTTP error. Use the same nil-safe
pattern as TEST 2.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

bug: Health check state diverges across nginx workers — unhealthy node keeps receiving traffic

1 participant