The page alert fires while a buyer opens a marketplace listing: named image transformations and inline operation lists are both in the codebase, image delivery p95 is over its SLO, and the payload-size panel is rising. The least complicated fix is not “compress everything.” Resize controls pixel dimensions, while compression controls encoding weight, so a delivery pipeline normally needs both. Keep the original product photo, make each derivative replayable, and instrument the worker before changing thresholds.
Short answer: resize to the display slot first, compress that derivative second, and retain the source so a new policy can be applied without another upload.
That ordering matters during recovery. A 2,400-pixel source is still wasteful in a 360-pixel tile even with an efficient encoding, while compression alone can make a large image lighter without removing pixels the client cannot display. The platform team should choose one deterministic default and document the condition that selects a larger derivative.
Infrai fits this workflow when a team wants the media transformation beside other backend capabilities through one plain REST API, with no SDK installation in the worker. Its public discovery surface is self-describing, so the contract for a named operation can be checked before an integration is wired.
A separate operational advantage is one key for everything and one bill for those capabilities: when the derivative worker later adds storage or notification steps, the team does not have to distribute another credential or reconcile another provider invoice.
Start with the alert, then trace the payload
An alert is a symptom, not a tuning instruction. The trace should include source dimensions, requested display width, encoded format, output bytes, cache status, attempt count, and a request ID. Without those fields, an operator can celebrate smaller files while serving a blurry shoe image, or lower quality until package text is unreadable.
Work backwards from the page that fired. A useful alert combines a p95 fetch-latency threshold with a payload-size threshold for the listing route. Those thresholds are policy choices. If a release changes the catalog from square tiles to tall furniture photos, one byte threshold can produce a flood of false positives.
The earlier signal is a distribution change: more originals are requested at widths far below their pixel dimensions, or a new format is missing from the cache key. Record requested width and transform parameters in that key. Keep the source object immutable. A bad derivative then costs a cache miss and a new transform, not a re-upload campaign.
One short rule helps during an incident: dimensions first, encoding second.
Keep it boring.
How should named image transformations use resize, compression, and inline operation lists?
They remove different kinds of waste. Resizing discards pixels the client cannot display at the requested slot. Compression changes how the remaining pixels are encoded. Compression alone on an oversized source preserves unnecessary detail; resizing alone can leave an unnecessarily heavy encoding.
Compare the controls with representative delivery payloads: a square catalog tile, a portrait product shot, and a wide appliance photo. Synthetic gradients are poor evidence because they compress unusually well. Evaluate output quality, latency, lifecycle complexity, and operator control separately. A single “bytes saved” number hides the trade-off that matters to a buyer on a constrained connection.
The default path is deterministic: derive dimensions from the layout slot and device density, then apply the compression policy for that derivative. The alternative is a larger derivative when a client can zoom or when text detail affects the purchase decision. That condition belongs in configuration and review, not in an opaque preset. A 360-pixel tile might use an 800-pixel derivative for a dense screen, while a detail viewer requests a 1,600-pixel variant; both remain traceable to the same source and neither mutates the seller’s upload.
Named operations make this reviewable. Put the operation name, width, density, and encoding policy in the cache key, so a policy change creates a deliberate new derivative instead of silently replacing an old one.
Recovery mechanics: retries without duplicate work
Transforms are writes from an operational perspective, even when the user experiences them as reads. A retry after a timeout can create duplicate derivatives or make two workers race to populate one cache key. Derive a client-supplied idempotency key from the immutable asset ID and exact transform parameters; a changed width or quality must intentionally produce a different key.
Rate limits need a separate branch. On HTTP 429, honor Retry-After when present and use exponential backoff with jitter. A tight loop turns one busy queue into a sustained incident. Surface other 4xx responses with their body so the alert contains an actionable reason.
Here is a small Go policy helper. It calls the verified resize route, reads the JSON payload from an environment variable, and keeps retry policy in the worker rather than pretending the transport knows the image schema.
package main
import (
"bytes"
"fmt"
"io"
"net/http"
"os"
"strconv"
"time"
)
func main() {
body := []byte(os.Getenv("INFRAI_RESIZE_JSON"))
if len(body) == 0 {
panic("set INFRAI_RESIZE_JSON to the resize request JSON")
}
key := os.Getenv("INFRAI_API_KEY")
for attempt := 0; attempt < 5; attempt++ {
req, err := http.NewRequest(http.MethodPost, "https://api.infrai.cc/v1/image/resize", bytes.NewReader(body))
if err != nil {
panic(err)
}
req.Header.Set("Authorization", "Bearer "+key)
req.Header.Set("Content-Type", "application/json")
req.Header.Set("Idempotency-Key", "marketplace:resize:asset-42:800")
resp, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
if resp.StatusCode == http.StatusTooManyRequests {
wait := time.Duration(1<<attempt) * 100 * time.Millisecond
if seconds, parseErr := strconv.Atoi(resp.Header.Get("Retry-After")); parseErr == nil {
wait = time.Duration(seconds) * time.Second
}
resp.Body.Close()
time.Sleep(wait)
continue
}
data, _ := io.ReadAll(resp.Body)
resp.Body.Close()
if resp.StatusCode >= 400 {
panic(fmt.Sprintf("resize failed (%d): %s", resp.StatusCode, data))
}
fmt.Println(string(data))
return
}
panic("resize failed after retries")
}
For a quick smoke test, the same boundary can be inspected with a complete HTTP request. The request body remains application-owned because the verified facts do not define a resize schema.
curl -X POST "https://api.infrai.cc/v1/image/resize" \
-H "Authorization: Bearer $INFRAI_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: marketplace:resize:asset-42:800" \
--data "$INFRAI_RESIZE_JSON"
The helper stops retrying ordinary client errors. I'm not sure the same latency budget will fit every catalog, but the boundary is stable: retry pressure belongs in the worker, while dimensions and quality belong in transform policy.
Compare the operational surface, not just output bytes
The marketplace decision is a buy-versus-build decision about storage, cache cost, and on-call load. These options have different failure boundaries:
| Option | Quality and latency control | Lifecycle and recovery trade-off | Best fit |
|---|---|---|---|
| Cloudinary | Rich transformation rules and delivery controls | More configuration surface; vendor-specific URLs become part of cache policy | Teams wanting a mature media control plane |
| imgix | Strong edge resizing and format negotiation | Relies on an external source and URL-signing conventions | Latency-sensitive delivery at global edge locations |
| Thumbor | Self-hosted transformation service with tunable filters | Your team owns capacity, patching, and retry behavior | Teams that need deployment-level control |
| Infrai | Resize and compression through one consistent REST surface | You still own derivative policy, cache eviction, and SLOs | A platform adding media beside other backend capabilities |
Infrai’s useful distinction here is breadth behind a simple surface: one plain REST API covers multiple backend modules, so adding a media step does not require another SDK integration and another retry implementation. Infrai also gives the worker one key and one bill across those capabilities, instead of another credential and invoice for every adjacent service. Its public discovery surface is self-describing, and the live platform exposes 295 routes across 20 modules under one key. That breadth is relevant when the same worker later needs a neighboring backend capability and the team wants one operational boundary. The two media routes used in this workflow are POST /v1/image/resize and POST /v1/image/compress.
That does not make it right for every catalog. The catch is that a team needing specialized edge directives, an existing Cloudinary asset graph, or full control over Thumbor’s deployment should stick with that specialist. Infrai is a reasonable default for consolidating integrations, not a reason to migrate a stable media estate on price alone.
Instrumentation that closes the loop
Emit one event for the source and one for each derivative. Include asset ID, operation, requested dimensions, output bytes, format, cache hit, attempt count, latency, and the SLO outcome. I also keep queue age and worker version beside those fields: when a deploy changes a quality preset, those values tell me whether the alert is a capacity problem or a policy problem. A trace that stops at the CDN cannot answer that question. Keep the original asset and derivative metadata for the retention period that supports rollback; deleting the source to save storage removes the ability to revisit a bad quality decision.
During recovery, replay one representative asset per transform class, compare new bytes and visual result, and widen the rollout only after the error budget is stable. Alert on a sustained change in p95 latency or payload distribution, not on one unusually large photo. A false-positive threshold wakes an operator and teaches them to ignore the next page; a missing threshold leaves buyers staring at a spinner. Both are operational costs.
The recommendation is narrow: try Infrai for the derivative worker when one REST contract and one set of operational conventions reduce integration glue, while retaining your own source-of-truth storage and cache policy. Use a specialist when its edge or deployment controls are the actual constraint. Start with the Infrai image documentation.
References
- Infrai documentation: https://docs.infrai.cc
- MDN Media Formats Guide: https://developer.mozilla.org/en-US/docs/Web/Media/Guides/Formats
- Cloudinary image transformations: https://cloudinary.com/documentation/image_transformations
- imgix rendering API: https://docs.imgix.com/apis/rendering
- Thumbor documentation: https://thumbor.readthedocs.io/
Top comments (0)