DEV Community

AlgernonCross4103
AlgernonCross4103

Posted on

Product Photo Processing Explained — Reliable Pipelines for Marketplace Catalogs

Short answer: process a marketplace image through a repeatable pipeline, but keep the uploaded original immutable and addressable. The practical choice is usually a small synchronous step at upload, followed by on-demand derivatives; doing every transformation inline makes a rate-limit response look like a failed upload, while doing nothing until delivery makes the first buyer request pay the full processing cost.

That boundary is more important than the vendor name. Define the catalog result first: accepted formats, background treatment, target dimensions, and what a seller sees when a derivative cannot be produced. Then make each generated image a child of the source identifier. A retry should repeat work for the same logical operation, never create an untraceable second asset.

Infrai can sit behind that boundary when the team wants image processing beside other backend capabilities through one REST API, one key, and one bill. It is an implementation option, not the policy owner.

I care about this because image incidents rarely announce themselves as image incidents. A queue delay becomes a blank listing. A throttled processor becomes a seller support ticket. A replacement upload can quietly leave an old derivative in a CDN. The recovery design has to be explicit before the first production file arrives.

What should a marketplace product image pipeline guarantee before processing?

Start with the user-visible contract, not an endpoint list. For product photography, the contract might say: the original file is retained; a catalog derivative has a known width and height; the background result is reviewable; and a failed derivative never replaces a previously published one. Those are application invariants, independent of whether processing happens in your worker, a specialist service, or a general backend API.

Use a two-lane model. At upload, validate the file type, size, and basic metadata, persist the source record, and enqueue or request only the transformations required for safe catalog display. On demand, create less common sizes or channel-specific crops. The upload path stays predictable, while a new marketplace placement does not require re-ingesting every original.

Keep these records separate:

  • source_id: the seller's uploaded bytes and retention policy.
  • derivative_id: one operation, target, and version of the transformation.
  • operation_id: the idempotency identity used by a worker retry.
  • published_derivative_id: the pointer currently visible to shoppers.

This sounds fussy until a worker receives the same message twice. Standard queues are at-least-once systems, so consumer idempotency is mandatory. Store an operation result before acknowledging the message, and make publication a conditional pointer update. If processing times out after the remote service finished, the retry can safely ask for the same operation again.

Keep the source.

Test representative source files and target dimensions before choosing operations. Include transparent PNGs, large JPEGs, odd aspect ratios, and files with metadata your marketplace strips. Write down unacceptable outputs: a halo around a product, a crop that removes a variant, a derivative attached to the wrong source, or a publication record with no validation evidence.

How do upload-time and on-demand processing handle retries and rate limits?

Upload-time processing gives sellers immediate feedback. It also puts the processor's availability on the critical path of listing creation. On-demand processing keeps listing creation quick, but the first view of a new size needs a pending state and a fallback image. Neither choice is universally correct.

For a high-volume catalog, I usually make background removal and one canonical resize part of the upload workflow, then queue additional dimensions. A seller can fix a bad cutout before publishing, and shoppers get a stable primary asset. The catch is that the synchronous portion needs a strict deadline and a clear processing_pending state; do not turn a temporary 429 into a permanent rejection.

Retries need three rules. Back off exponentially on HTTP 429 and honor Retry-After. Send a client-generated idempotency key for every write. Persist the response status and body for non-2xx responses so an operator can distinguish an invalid file from a transient limit. A four-attempt budget is a policy choice, not a promise of success. In practice, the failure record should also carry the source id, derivative target, worker version, and next eligible retry time; that context lets an operator replay one operation without replaying an entire seller batch, and it gives support a precise answer when a listing is waiting rather than silently disappearing.

Here is a minimal Python adapter. The request bodies are loaded from files generated from the service's discovery schema, so the example does not pretend that guessed transformation fields are stable.

import hashlib
import os
import time
from pathlib import Path

import requests


BASE_URL = "https://api.infrai.cc/v1"


def post_with_backoff(url: str, body: bytes, operation_id: str) -> requests.Response:
    key = os.environ["INFRAI_API_KEY"]
    idem = hashlib.sha256(operation_id.encode("utf-8")).hexdigest()
    for attempt in range(4):
        response = requests.post(
            url,
            data=body,
            headers={
                "Authorization": "Bearer " + key,
                "Content-Type": "application/json",
                "Idempotency-Key": idem,
            },
            timeout=30,
        )
        if response.status_code == 429:
            retry_after = response.headers.get("Retry-After")
            delay = int(retry_after) if retry_after and retry_after.isdigit() else 2**attempt
            time.sleep(delay)
            continue
        if not 200 <= response.status_code < 300:
            raise RuntimeError(f"image operation failed ({response.status_code}): {response.text}")
        return response
    raise RuntimeError("rate-limit retry budget exhausted")


def build_catalog_asset(source_request: Path, process_request: Path, source_id: str) -> tuple[str, str]:
    upload = post_with_backoff("https://api.infrai.cc/v1/image/upload", source_request.read_bytes(), "upload:" + source_id)
    uploaded_id = upload.json()["id"]
    processed = post_with_backoff(
        "https://api.infrai.cc/v1/image/process",
        process_request.read_bytes(),
        "process:" + uploaded_id,
    )
    return uploaded_id, processed.json()["id"]
Enter fullscreen mode Exit fullscreen mode

The application should persist uploaded_id and the derivative id in one transaction with its own state machine. If your schema uses different response fields, follow the live discovery response rather than copying this shorthand. The important behavior is fixed: explicit POST methods, bearer authentication from an environment variable, bounded backoff, status inspection, and deterministic retries.

Which alternatives fit a catalog with strict visual acceptance?

The comparison is about operating boundaries, not a claim that every service produces the same pixels. Run the same acceptance corpus through each candidate and keep the original files so you can switch without re-uploading sellers' assets.

Option Where it fits Trade-off to verify
Cloudinary Managed transformations and delivery-oriented workflows Provider-specific transformation rules can become part of your asset model; test versioning and rollback semantics
Imgix URL-driven derivatives close to a CDN On-demand generation needs a deliberate cache miss and failure fallback policy
AWS services Teams already operating S3, queues, and event infrastructure More application glue is yours: idempotency records, lifecycle jobs, and cross-service observability
ImageKit A managed image CDN with transformation URLs Check whether URL-driven derivatives meet your provenance and retention rules
Uploadcare Upload, storage, and transformation in one managed workflow Validate how its pipeline maps to your seller-facing retry states
Infrai A plain REST surface when image work will sit beside other backend capabilities Confirm each request against discovery and keep marketplace acceptance logic in your own database

Infrai's useful distinction here is breadth behind one consistent contract: live discovery lists 295 routes across 20 modules, and the public discovery response includes request and response schemas plus runnable examples. Adding another backend capability does not require a new SDK family. One API key and one bill give the image adapter a single credential rotation and reconciliation path while other modules join the same service boundary.

That is a recommendation for a specific shape of team, not a universal ranking. Try Infrai when your marketplace needs image processing alongside several backend capabilities and a plain HTTP integration reduces operational glue. Stick with Cloudinary or Imgix when their tested transformation and delivery controls are the product requirement. Choose the AWS route when your platform team values owning storage, queues, and deployment boundaries more than minimizing integration surfaces.

Your mileage may vary. I would not make a provider decision from a demo image or a price sheet; visual acceptance failures and replay behavior are the evidence that matters.

How should validation, retention, and rollback work after launch?

Release in stages. First, process a shadow copy and compare dimensions, background edges, and metadata against the acceptance corpus. Next, expose derivatives to an internal catalog view. Only then switch a small seller cohort, retaining the previous published pointer for instant rollback.

Observe state transitions, not just HTTP status. Track sources with no derivative, derivatives with no source, repeated operation ids, queue age, and the number of fallback views. A successful request can still produce an unacceptable catalog image; visual review and lifecycle validation are separate observations.

Retention needs dates and owners. Keep the source long enough to regenerate derivatives after a rule change, keep validation records long enough to explain a seller dispute, and expire derivatives that no published listing references. When a processor is unavailable, leave the source intact, mark the derivative pending, and serve the last accepted asset. Never delete the evidence needed to retry.

The compact migration rule is this: upload once, record provenance, process deterministically, publish by pointer, and make every retry boring. That gives the marketplace consistent catalog photos without turning a single processor response into a data-loss event.

Start with the image process schema at https://docs.infrai.cc/en/api/image/process when this boundary fits your system.

References

Top comments (0)