Skip to content

[v3] Add dragonfly backend error handling and E2E tests - #2043

Merged
imeoer merged 3 commits into
dragonflyoss:v3from
bergwolf:dragonfly-backend-error-handling
Aug 27, 2026
Merged

[v3] Add dragonfly backend error handling and E2E tests#2043
imeoer merged 3 commits into
dragonflyoss:v3from
bergwolf:dragonfly-backend-error-handling

Conversation

@bergwolf

Copy link
Copy Markdown
Member

This PR implements proper error handling for Dragonfly backend with differentiated retry policies for prefetch vs on-demand reads. Adds configurable retry budgets, fallback throttling, and proper error classification, plus a new E2E test workflow to validate the changes.

  • Prefetch reads retry up to 10 times before failing without fallback, while on-demand reads retry 3 times then fall back to origin registry. Rate limiting (429) triggers immediate fallback for on-demand reads and immediate failure for prefetch. Forbidden errors (403) are terminal for both read types.

  • Adds fallback limiter to throttle consecutive origin requests with configurable interval. Implements proper error propagation with throttled marker for rate limiting scenarios. Updates telemetry metrics to track backend read attribution between proxy and origin.

Example workflow run: https://github.com/bergwolf/nydus/actions/runs/32847782111

Implements sophisticated error handling for Dragonfly backend with differentiated retry policies
for prefetch vs on-demand reads. Adds configurable retry budgets, fallback throttling, and
proper error classification.

Prefetch reads retry up to 10 times before failing without fallback, while on-demand reads
retry 3 times then fall back to origin registry. Rate limiting (429) triggers immediate
fallback for on-demand reads and immediate failure for prefetch. Forbidden errors (403) are
terminal for both read types.

Adds fallback limiter to throttle consecutive origin requests with configurable interval.
Implements proper error propagation with throttled marker for rate limiting scenarios.
Updates telemetry metrics to track backend read attribution between proxy and origin.

Signed-off-by: Peng Tao <bergwolf@hyper.sh>
@bergwolf bergwolf added the enhancement New feature or request label Aug 25, 2026
@bergwolf
bergwolf requested review from a team as code owners August 25, 2026 12:42
@bergwolf
bergwolf requested review from ClementMaH, CooooolFrog, EvanCley, gaius-qi, mingcheng and yyzai384 and removed request for a team August 25, 2026 12:42
@bergwolf bergwolf changed the title Add dragonfly backend error handling and E2E tests [v3] Add dragonfly backend error handling and E2E tests Aug 25, 2026
This commit adds comprehensive end-to-end testing infrastructure for Dragonfly integration,
including GitHub Actions workflow, configuration files, and test implementations.

The new E2E workflow tests both SDK-proxy and fallback modes with Dragonfly 2.4.3,
validating nydus image distribution through the Dragonfly P2P network. Configuration
files support multiple test scenarios including strict and fallback modes for both
proxy and SDK integration patterns.

Registry backend is extended with Dragonfly support to enable P2P-based image
distribution, improving scalability and reducing registry load for large-scale
deployments.

Signed-off-by: Peng Tao <bergwolf@hyper.sh>
@bergwolf
bergwolf force-pushed the dragonfly-backend-error-handling branch from 092dc33 to d209e73 Compare August 25, 2026 13:19
@bergwolf
bergwolf requested review from imeoer and a balanced review from Copilot August 25, 2026 13:21

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Adds Dragonfly-aware retry, fallback, throttling, telemetry, and E2E coverage for registry reads.

Changes:

  • Differentiates prefetch and on-demand Dragonfly failure policies.
  • Adds delayed prefetch rescheduling and fallback telemetry.
  • Introduces Dragonfly service configurations and CI workflows.

Reviewed changes

Copilot reviewed 22 out of 22 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
.github/workflows/e2e-dragonfly.yml Adds Dragonfly E2E CI jobs.
docs/nydus.md Documents policies, configuration, and metrics.
misc/dragonfly/dfdaemon.yaml Configures the test dfdaemon.
misc/dragonfly/manager.yaml Configures the Dragonfly manager.
misc/dragonfly/scheduler.yaml Configures the Dragonfly scheduler.
misc/dragonfly/nydus-sdk-fallback.yaml Defines SDK fallback mode.
misc/dragonfly/nydus-sdk-strict.yaml Defines SDK strict mode.
misc/dragonfly/nydus-proxy-error-fallback.yaml Configures fallback error tests.
misc/dragonfly/nydus-proxy-error-strict.yaml Configures strict error tests.
nydus-backend/src/lib.rs Adds throttling markers and read attribution.
nydus-backend/src/registry/dragonfly.rs Classifies Dragonfly SDK failures.
nydus-backend/src/registry/http.rs Exposes a non-retrying HTTP client.
nydus-backend/src/registry/mod.rs Implements retry and fallback policy.
nydus-config/src/lib.rs Adds policy and rescheduling settings.
nydus-core/src/lib.rs Manages the prefetch stop flag.
nydus-storage/src/prefetch.rs Reschedules throttled prefetches.
nydus-telemetry/src/metrics.rs Adds policy and fallback metrics.
nydus/src/bin/nydus/fuse.rs Passes prefetch settings and stops workers.
tests/e2e/dragonfly_test.go Adds Dragonfly integration tests.
tests/e2e/fanotify_test.go Uses the shared environment helper.
tests/e2e/harness.go Adds the shared environment helper.
tests/e2e/uffd_fault_test.go Prevents GC deadlocks during UFFD tests.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread nydus-backend/src/registry/dragonfly.rs Outdated
Comment thread nydus-backend/src/registry/mod.rs
Comment thread nydus-backend/src/lib.rs
Comment thread tests/e2e/dragonfly_test.go Outdated
Comment on lines +298 to +304
postInject(t, http.StatusTooManyRequests, 1)
defer clearInject(t)
wipeCacheDir(env.cacheDir)
cleanup := env.startFuse(t)
defer cleanup()
_, data, err := readMountedFile(t, env.mountpoint)
require.NoError(t, err)
@bergwolf
bergwolf force-pushed the dragonfly-backend-error-handling branch from 6ae619c to 541077f Compare August 26, 2026 13:25
Add proper error classification for mid-stream failures and improve
backend attribution for CRC validation errors. The changes introduce retry
logic for Dragonfly stream failures with proper fallback mechanisms when
retry budget is exhausted.

New telemetry metrics track CRC errors by backend target (origin/proxy)
and Dragonfly stream failures. The attribution system now correctly
assigns validation failures to the appropriate backend without requiring
active read operations.

Enhanced test coverage includes scenarios for mid-stream failures,
retry exhaustion, and proper error attribution across the storage stack.

Signed-off-by: Peng Tao <bergwolf@hyper.sh>
@bergwolf
bergwolf force-pushed the dragonfly-backend-error-handling branch from 541077f to 164ffc0 Compare August 26, 2026 13:28
@bergwolf
bergwolf requested a balanced review from Copilot August 26, 2026 13:31

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 23 out of 23 changed files in this pull request and generated 4 comments.

Suppressed comments (6)

Previously missed (5) — in code that hasn't changed since the last review.

nydus/src/bin/nydus/fuse.rs:340

  • The stop flag is raised only when session.serve() returns Ok; any outer error from signal setup, controller-thread creation, or result-channel receive exits via ? first and leaves the detached prefetcher rescheduling indefinitely. Capture the serve result, raise the flag on both paths, and only then propagate the error.
        // The filesystem is unmounted: wind down the detached prefetch thread
        // (it may be sleeping towards a rescheduled throttled-blob retry).
        if let Some(stop) = prefetch_stop {
            stop.store(true, std::sync::atomic::Ordering::Relaxed);
        }

nydus-config/src/lib.rs:196

  • max_retries is a retry budget in addition to the initial attempt: the fallback loop stops when attempts > max_retries, and the test with max_retries: 1 expects two origin requests. The current “3 attempts” wording is off by one; the default permits four total attempts.
    /// The maximum number of retry attempts per request, applied by the HTTP
    /// client's retry middleware on direct origin requests — including origin
    /// requests issued as Dragonfly fallbacks, so the default of 3 is what
    /// bounds "origin failing 3 attempts" before a fallback read errors out.

docs/nydus.md:826

  • This table describes http.max_retries as the total number of failed origin attempts, but the implementation performs one initial attempt plus that many retries. Clarify the total to avoid understating origin traffic and fallback latency.
	| Proxy `429` | No retry, no origin fallback; the blob's prefetch fails and is rescheduled after a random `prefetch.retry_delay_min`–`prefetch.retry_delay_max` delay | No Dragonfly retry; fall back to the origin through the fallback throttle; the origin failing `http.max_retries` attempts → IO error |

nydus-config/src/lib.rs:308

  • The canonical config/registry.example.yaml is now stale: it still says http.max_retries controls Dragonfly SDK retries, says all Dragonfly failures fall back, and does not expose any of these new policy fields. Update that example with the differentiated policy and configurable budgets so users are not guided to ineffective settings.
    #[serde(
        default = "default_dragonfly_fallback_interval",
        with = "humantime_serde"
    )]
    pub fallback_interval: Duration,

.github/workflows/e2e-dragonfly.yml:368

  • The newly added misc/dragonfly/nydus-proxy-error-strict.yaml fixture is never referenced; this job always supplies only the fallback fixture. Add the strict fixture to a matrix/run if it is intended coverage, or remove the dead configuration.
            NYDUS_CONFIG=${{ github.workspace }}/misc/dragonfly/nydus-sdk-fallback.yaml \
            NYDUS_CACHE_DIR=/tmp/nydus-dragonfly/cache-proxy-fallback \
            NYDUS_PROXY_ERROR_CONFIG=${{ github.workspace }}/misc/dragonfly/nydus-proxy-error-fallback.yaml \

nydus-backend/src/registry/mod.rs:705

  • A fallback earlier in the same logical read sets READ_SERVED_BY to Origin, but a subsequent Dragonfly success (for example during a 401 auth handshake or after evicting an expired redirect) does not restore it. The metered read and any CRC error are then incorrectly attributed to origin even though Dragonfly supplied the final bytes. Record Proxy on this success path.
            let err = match self.request_dragonfly(dragonfly, url, headers.clone(), context) {
                Ok(response) => return Ok(response),

Comment on lines +413 to +417
.and_then(|v| v.parse::<usize>().ok())
.unwrap_or(0);
let body = runtime().block_on(async {
let mut body = Vec::with_capacity(capacity);
self.reader.read_to_end(&mut body).await?;
Comment thread docs/nydus.md
Comment on lines +904 to +906
- `backend_dragonfly_read_errors{class,kind}` — Dragonfly read failures by
failure class (`rate_limited`, `forbidden`, `timeout`, `connect`,
`server_error`, `other`) and read kind (`ondemand`, `prefetch`).
require.Error(t, err)
})

t.Run("status_429_ondemand_fallback", func(t *testing.T) {
Comment on lines +398 to +403
"Origin requests issued as Dragonfly fallbacks",
),
backend_fallback_read_errors: counter(
&registry,
"backend_fallback_read_errors",
"Failed origin requests issued as Dragonfly fallbacks",
@imeoer
imeoer merged commit 64c863b into dragonflyoss:v3 Aug 27, 2026
17 checks passed
@bergwolf
bergwolf deleted the dragonfly-backend-error-handling branch August 27, 2026 02:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants