Skip to content

on-demand sync: stale .sync staging after killed sync causes all by-tag manifest GETs to hang #4357

Description

@jvallery

zot version: v2.1.20 (-events-imagetrust-lint-metrics-mgmt-profile-scrub-search-sync-ui-userprefs binary), filesystem storage on an NFS mount (Synology, nfsvers=4.1, hard), dedupe+gc on, sync extension with 8 onDemand registries.

What happened (production, 2026-08-25): an in-flight on-demand sync of a ~10 GB multi-arch image (docker.io/gpustack/runner) was interrupted (client connection cut at our HTTP writeTimeout, then the pod was restarted while a second demand for the same image was in flight). After restart, a stale staging tree remained at <repo>/.sync/<uuid>/ (~18.5 GiB). From then on:

  • Every by-tag manifest GET on EVERY repository hung indefinitely (each triggers an upstream freshness sync that appeared to queue forever — even for tiny, already-cached images on unrelated repos/registries).
  • By-digest manifest GETs and /v2/_catalog remained fast (local store healthy).
  • The process was near-idle (few mCPU), no Copy layer / sync progress log lines, no errors logged; readiness/liveness stayed green.
  • Upstream (Docker Hub) and storage were verified healthy from the same host at the same time.

Recovery: stop zot, delete all .sync staging dirs, start zot → by-tag GETs immediately behaved normally (~2 s freshness syncs) and re-warms of the same big image completed fine (with a plain post-download commit/verify phase of up to ~12 min for ~10 GB on NFS, which is expected and distinct from the hang).

Suspicion: the on-demand sync worker pool / per-image demand channel can be exhausted or deadlocked when stale staging from a killed sync is present (possibly interacting with image already demanded, waiting on channel bookkeeping across restart), starving every subsequent freshness sync. A startup sweep of orphaned .sync dirs (or ignoring them for demand accounting) would likely prevent the state entirely.

Config highlights: onDemand: true x8 registries, maxRetries: 3, retryDelay: 1m, maxRetryDelay: 10m, SyncTimeout default 3h, storage gc 1h. Happy to provide fuller logs/config on request.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    awaiting-feedbackbugSomething isn't workingrm-externalRoadmap item submitted by non-maintainers

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions