Recipes: media and files

Photos, videos and documents are where offline queues earn their keep: large, slow, and easy to lose. These recipes cover progress, pipelines, chunking and cleanup.

First, make the file permanent

Image pickers and cameras often return a temporary file that the system may delete before the upload runs. Copy it into your app's own storage before you enqueue, and put that path in the payload.

Upload with progress, cancel and retry

fetch in React Native does not report upload progress. Use XMLHttpRequest.

The list with progress bar, retry and cancel buttons is on React hooks.

Compress, then upload

Two steps, two jobs. Compression needs no network, so it runs immediately, offline. Upload waits for connectivity.

A whole album, politely

Two-step upload with a signed URL

Get a pre-signed URL from your API, then PUT the file to storage (S3, GCS, Azure Blob).

Step 1 uses the job id as idempotency key, so a retry returns the same object key and does not create orphans.

Chunked uploads

For files too large for one request, one job per chunk, plus a finalize job when all chunks are in. Chunk ids are deterministic, so re-enqueueing is harmless, and progress survives restarts.

With limits: { uploadChunk: { concurrency: 3 } } you get three chunks in parallel, each retried independently on its own.

Resumable upload in one job (generator)

An async function* handler is a natural fit for sequential chunking: every yield is a point where cancellation takes effect, and a retry resumes from where the server says it left off.

Retries resume, they do not restart

A thrown error makes the queue run the generator again from the top, but getServerOffset makes the next run skip what is already uploaded.

Big videos: native background upload

For videos, prefer the OS uploader so the transfer continues when the user leaves the app. QueueKit tracks it with ctx.detach(). The full walkthrough, including reattaching after a restart, is on Background and native tasks.

Downloads and prefetching

A low priority keeps prefetching from delaying user actions, and ttlMs drops requests the user no longer needs (they scrolled past). To prefetch only on Wi-Fi, use a separate queue with a Wi-Fi-only monitor.

Clean up temp files

Delete the local copy only when you are sure it is no longer needed: after success, or after the user discards a failed job.

Also sweep your upload directory at startup for files with no matching job, to catch leftovers from crashes: