VolumeCache is a primitive in the Runpod Python SDK (runpod >= 1.7.14) that mirrors local cache directories to an attached network volume and reconciles them on each cold start. It turns a repeated multi-GB model download into a one-time cost per endpoint by restoring cached files at worker startup and syncing new downloads back after the handler runs.
Use VolumeCache when you want cache persistence across worker recycling but still want inference reads to hit fast local disk instead of the network mount.
How it works
VolumeCache keeps a browsable mirror of your cache directories under {volume_path}/.cache/{namespace} on the attached network volume and reconciles it against the container in two phases:
- Hydrate: on cold start, files that are missing or newer on the volume mirror are copied into the local cache directory.
- Sync: after the handler runs (or on context-manager exit), files that are missing or newer in the local cache directory are copied back to the volume mirror.
- Files smaller than 256 KiB are packed into a single
small.tararchive, collapsing per-file metadata round-trips on the volume. - Larger files are copied unpacked into a
big/subdirectory, in parallel across a thread pool. - A versioned
manifest.jsonis written last and acts as the atomic commit marker — a mirror without a valid manifest is treated as absent, so partial syncs never corrupt the cache.
Requirements
- A network volume attached to your endpoint (mounted at
/runpod-volume). - The
runpodPython SDK installed in your worker image.
/runpod-volume), every operation is a safe no-op and your handler still runs.
Basic usage
The recommended pattern is to wrap your model load in aVolumeCache context manager. Hydration runs on enter, and sync runs on exit:
handler.py
with block exits. On every subsequent cold start (including new workers spun up by autoscaling), the volume mirror is copied back into HF_CACHE before pipeline() runs, so the download is skipped.
Explicit hydrate and sync
If your worker’s startup and shutdown phases aren’t in the same code block, callhydrate() and sync() directly:
sync() runs on a background daemon thread and returns immediately, so the with block doesn’t block on the copy. A process-exit hook joins outstanding syncs so short-lived processes still complete the sync before exiting. Pass background=False when you need the call to block until the sync finishes.
Constructor arguments
Behavior notes
- Autoscaling safe. Each worker reads the same manifest and mirror, so spun up by autoscaling all restore from the same cache on cold start.
- Last-writer-wins. Under concurrent workers, the mirror reflects whichever worker synced most recently. There is no locking or merge.
- Cold-scale write amplification. If N workers cold-start simultaneously against an empty mirror, each may download the model and sync a full copy back. There is no coordination between concurrent syncs.
- Symlinks are not followed. Every archive member and every big-file destination is checked to resolve inside one of the configured
dirsbefore any write, so a mirror entry cannot be used to write outside the cached directories. - Idempotent. Re-running
hydrate()orsync()when nothing has changed copies zero files. - Orphaned large files are not pruned. If a large file is deleted or renamed locally, its
big/<relpath>copy stays on the volume. Volume space grows across model-version swaps unless you clear the mirror manually.