Caching Overview
PreviewProxy uses a two-level cache to avoid redundant fetches and transforms. Once an image has been fetched and processed, subsequent requests for the same image and parameters are served from cache.
Two-level cache architecture
L1: In-memory cache
The L1 cache stores transformed images in RAM using Moka, a high-performance concurrent cache library. It is the fastest cache level - a cache hit here avoids both disk I/O and recomputation.
The L1 cache is lost when the process restarts.
L2: Disk cache
The L2 disk cache has two sub-stores, both rooted under PP_CACHE_DIR:
| Sub-store | Path | What is stored |
|---|---|---|
| Transformed | <PP_CACHE_DIR>/ | Final transformed image (the result sent to clients) |
| Origin | <PP_CACHE_DIR>/origin/ | Raw fetched bytes before any transform is applied |
The origin sub-store allows the same source file to be fetched only once. If the same URL is later requested with different transform parameters, PreviewProxy reads the raw bytes from the origin sub-store and applies the new transforms locally, skipping the upstream fetch entirely. This applies to HTTP and S3 sources.
For HTTP sources the TTL of an origin entry is derived from the upstream response headers (Cache-Control: max-age or Expires), falling back to PP_CACHE_DISK_TTL_SECS when no headers are present.
Cache key
The transformed cache key is derived from:
- Source image URL - the full upstream URL
- Transform parameters - all request parameters except
sig
The origin cache key is derived from the source URL only (no transform parameters).
Two requests with the same URL and parameters always resolve to the same cache key, regardless of parameter order.
Request flow
Inflight deduplication
If multiple requests for the same image and parameters arrive simultaneously (before the first request has finished), PreviewProxy ensures that only one fetch and transform is performed. All other concurrent requests wait for the result and then receive it. This prevents thundering herd problems under high concurrency.
Configuration reference
L1 (memory) settings
| Variable | Default | Description |
|---|---|---|
PP_CACHE_MEMORY_MAX_MB | 256 | Maximum size of the in-memory cache in megabytes |
PP_CACHE_MEMORY_TTL_SECS | 3600 | How long entries remain in the memory cache (seconds) |
L2 (disk) settings
| Variable | Default | Description |
|---|---|---|
PP_CACHE_DIR | /tmp/previewproxy | Directory where cached files are written |
PP_CACHE_DISK_TTL_SECS | 86400 | How long entries remain on disk before expiry (seconds) |
PP_CACHE_DISK_MAX_MB | unlimited | Maximum total size of the disk cache in megabytes |
Maintenance
| Variable | Default | Description |
|---|---|---|
PP_CACHE_CLEANUP_INTERVAL_SECS | 600 | How often the background job scans for and removes expired disk cache entries (seconds) |
PP_CACHE_DISK_MAX_MB is not set by default, meaning disk usage is unbounded. In production it is strongly recommended to set this to prevent disk exhaustion. See Cache Tuning for guidance.