Skip to content

fix: Make HttpLoadQueuePeon degrade gracefully instead of throwing on fetch failure - #20128

Open
waterWang wants to merge 1 commit into
apache:masterfrom
waterWang:fix-httpLoadQueuePeon-degraded-fetch
Open

fix: Make HttpLoadQueuePeon degrade gracefully instead of throwing on fetch failure#20128
waterWang wants to merge 1 commit into
apache:masterfrom
waterWang:fix-httpLoadQueuePeon-degraded-fetch

Conversation

@waterWang

Copy link
Copy Markdown

Description

Fixes #19950

When a historical server returns a non-200/404 response or is unreachable
during fetchSegmentLoadingCapabilities(), the HttpLoadQueuePeon constructor
throws an RE. This exception propagates through
LoadQueueTaskMaster.resetPeonsForNewServers() into
PrepareBalancerAndLoadQueues, which is the first duty in the
HistoricalManagementDuties group. The top-level
DruidCoordinator.DutiesRunnable.run() catches and logs the exception, but
segment management (loading, balancing, handoffs) stops entirely for all
servers — not just the unhealthy one. Ingestion tasks back up waiting for
handoff.

Changes

  • fetchSegmentLoadingCapabilities(): Instead of throwing RE on non-200/404
    responses or any Throwable, return default SegmentLoadingCapabilities
    derived from the configured batch size, with a warning log. The peon is still
    created, the server is still managed with conservative defaults, and the rest
    of the duty group proceeds normally.
  • Mirror the existing 404 branch's fallback behavior (already returned default
    capabilities).

Key design decisions

  • The 404 branch already existed and returned default capabilities. The fix
    extends this same graceful degradation to non-200 responses and exceptions.
  • log.makeAlert() is preserved for non-200 responses so operators still get
    alerted about the unhealthy server.
  • The catch block now logs a warning instead of throwing, keeping the
    Coordinator ticking.

Release notes

Fixed a bug where a single unhealthy or unreachable historical server could
stall all segment loading and balancing across the cluster.

… fetch failure

When a historical server returns a non-200/404 response or is unreachable,
fetchSegmentLoadingCapabilities() throws an RE, which propagates through
LoadQueueTaskMaster.resetPeonsForNewServers() into PrepareBalancerAndLoadQueues.
The top-level DruidCoordinator.DutiesRunnable.run() catches and logs it, but
segment management stops entirely for ALL servers — not just the unhealthy one.

Fix: degrade gracefully by returning default SegmentLoadingCapabilities derived
from the configured batch size, with a warning log. The peon is still created,
the server is still managed with conservative defaults, and the rest of the
duty group proceeds normally.

@FrankChen021 FrankChen021 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Severity Findings
P0 0
P1 0
P2 2
P3 0
Total 2

The review found two P2 correctness and lifecycle risks in the fallback capability handling.

Reviewed 1 of 1 changed files.


This is an automated review by Codex GPT-5.6-Luna(max)

}
catch (Throwable th) {
throw new RE(th, "Received error while fetching historical capabilities from Server[%s].", serverId);
log.warn(th, "Failed to fetch loading capabilities from server[%s]. Using default capabilities.", serverId);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P2] Fallback swallows fatal and interruption signals

The Throwable catch now converts fatal Errors and InterruptedException into a normal peon. This can mask JVM-level failures and clear interruption without restoring the thread flag. Catch only expected request/parsing exceptions, while rethrowing fatal errors and preserving interruption.

throw new RE(th, "Received error while fetching historical capabilities from Server[%s].", serverId);
log.warn(th, "Failed to fetch loading capabilities from server[%s]. Using default capabilities.", serverId);
int batchSize = config.getBatchSize() == null ? 1 : config.getBatchSize();
return new SegmentLoadingCapabilities(batchSize, batchSize);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P2] Transient failures permanently throttle the peon

serverCapabilities is initialized once and cached for the peon's lifetime. After a temporary timeout, 5xx, or malformed response, the stored fallback remains active indefinitely; with no configured batchSize this reduces normal and turbo loading to one segment per batch. Retry capability discovery or refresh the fallback.

@kfaraz

kfaraz commented Aug 25, 2026

Copy link
Copy Markdown
Contributor

@waterWang , does this mean we don't need #19550 ?
cc: @abhishekrb19

@abhishekrb19

Copy link
Copy Markdown
Contributor

@waterWang , does this mean we don't need #19550 ? cc: @abhishekrb19

@waterWang since #19950 already addresses the bug and has now been merged, we can close this one out.

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.

4 participants