Image Pipeline
Vylux handles images on a synchronous request path optimized for low latency and high cache hit rates.
Endpoints
/img/:sig/:opts/*: transform and return an image immediately/original/:sig/*: proxy the original object/thumb/:sig/*: proxy generated image assets
/img core flow
- parse the output format and source key from the request path
- parse
opts, currently supportingw,h, andq - validate the HMAC signature
- check the memory LRU
- check the media-bucket storage cache
- on a miss, fetch the original from the source bucket
- transform the image with libvips
- write the result into the memory LRU synchronously and the storage cache asynchronously
- return the image bytes with CDN-friendly headers
Signing canonicalization
Vylux does not sign the raw browser URL string directly. It first canonicalizes:
optsintow -> h -> qorder- the encoded source path into a decoded object key
jpegintojpg
This prevents logically equivalent requests from producing different signatures or cache keys.
Cache layers
| Layer | Role | Write timing |
|---|---|---|
| memory LRU | hot results inside one process | synchronous |
| media-bucket storage cache | shared derived-image cache across processes and pods | asynchronous |
| CDN | public distribution layer | driven by response headers |
Current response behavior includes:
Cache-Control: public, max-age=31536000, immutableETagbased on the returned bytesVary: Accept
Cache path
Real-time image results are written to:
cache/{processing_hash}.{format}
processing_hash is derived from the source key and transformation parameters, not from the upstream job hash field.
singleflight and concurrency
The synchronous image path uses two singleflight groups:
sourceFlight: suppress duplicate fetches of the same original imageprocessFlight: suppress duplicate transforms for the same source-plus-options combination
This matters when a cold cache receives a burst of identical requests.
/original and /thumb
These two endpoints do not transform content:
/originalproxies objects from the source bucket/thumbproxies already-generated image assets from the media bucket
Both require HMAC-signed URLs, but /thumb uses a dedicated thumb signing domain so signatures cannot be reused across /thumb and /original.
How image:thumbnail differs
Although both features deal with images, they serve different purposes:
| Path | Mode | Output location | Typical use |
|---|---|---|---|
/img | synchronous | cache/{processing_hash}.{format} | browser-facing dynamic image delivery |
image:thumbnail | asynchronous | images/{prefix}/{hash}/{variant}.{format} | stable pre-generated variants |
image:thumbnail does not route through /img. The worker generates named variants directly.
Error semantics
The image path is intentionally strict:
400: invalid parameters or unsupported format403: invalid signature404: missing source object422: source exists but cannot be processed502: temporary source-storage failure500: unexpected internal error
There is no pretend-success fallback image. Failures remain visible to upstream callers and observability tooling.