Stage originals and defer optimization to a background job #167
Labels
No labels
kind
bug
kind
enhancement
wayfinder
grilling
wayfinder
map
wayfinder
prototype
wayfinder
research
wayfinder
task
workflow
needs-info
workflow
needs-triage
workflow
ready-for-agent
workflow
ready-for-human
workflow
wontfix
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
rosa/vernier#167
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Part of the "defer media processing to a background job" spec (PR #165; ADR-0020,
ADR-0021). This is the core slice: optimization moves off the upload request onto
the existing apalis queue.
What to build
Change what
create_mediadoes — the single domain op both the web editor and theMicropub
POST /mediaendpoint already call (ADR-0019). It stops optimizinginline. Instead it performs only the cheap, safety-critical request-path checks
(magic-byte type sniff against the JPEG/PNG/WebP allowlist and the pre-optimization
size ceiling), mints the
MediaId, stages the raw bytes on the durable data volumevia a new staging port, inserts a Processing Media, enqueues an
optimize_mediajob, and returns the (Processing) Media. Both adapters stay untouched — they still
hand raw bytes to one op and get a
Mediaback.A new apalis job (following the mailer/webmention shape: a serde payload carrying
the
MediaId, ports supplied viaData<…>, registered on theMonitor) runs thedeferred pipeline — decompression-bomb guard, decode, EXIF-orientation, metadata
strip, downscale, AVIF re-encode — then writes the rendition and dimensions, flips
the Media to Ready, and deletes the staged original. The job is idempotent:
a no-op if the Media is already Ready, and a missing staged file counts as
already-done. The worker runs at low, fixed concurrency because AVIF encoding is
CPU-bound and competes with request-serving threads.
This slice covers the happy path (a valid image ends up Ready). Permanent/transient
failure classification is the next slice; here, treat any pipeline error as a
retryable job failure for now.
Staged originals live on the data volume (beside
vernier.db, never/tmp, never aSQLite table), keyed by Media id, and are deleted once the rendition is stored.
Acceptance criteria
create_mediano longer optimizes inline; it stages bytes, records a Processing Media, and enqueues oneoptimize_mediajob.optimize_mediaworker runs the full pipeline, stores the AVIF rendition + dimensions, flips the Media to Ready, and deletes the staged file.GET /media/{id}404s while Processing and 200s (image/avif) once the job runs.enable_background_jobs: false) covers upload → Processing → run job → Ready → serve, including a Post published against a still-Processing Media whose Photo appears only after processing.Blocked by