DEVELOPMENT

How to process 5,000 image downloads without crashing your server

Large download jobs fail when they are treated like one browser request. Use queues, bounded concurrency, retries and resumable progress instead.

TTWE EditorialSep 16, 2026 · 4 min read

Do not keep the browser request open

A job that may take minutes or hours should not depend on one HTTP request remaining alive. The browser should create a job record and return immediately. A background worker or scheduled process can then handle the queue in small batches.

Store progress in the database: total items, processed items, failures, last attempted item and job status. This lets the UI show progress and lets the worker resume after a crash.

Bound concurrency

More parallel downloads are not automatically faster. Too much concurrency can exhaust PHP workers, memory, file descriptors, outbound connections or the source server. Start with a conservative concurrency level and measure throughput, error rates and resource usage.

For shared hosting, a cron-driven worker processing a small batch every minute may be more reliable than attempting dozens of parallel requests.

Stream files instead of buffering them

Avoid loading an entire large image into memory before writing it. Stream the response to disk or object storage where the HTTP library supports it. Validate content type and size, generate a deterministic filename and write to a temporary path before moving the completed file into place.

If image optimization is required, separate downloading from resizing. The download queue should not be blocked by CPU-heavy transformations.

Retry intelligently

Retry transient failures such as timeouts and 5xx responses with exponential backoff and a maximum attempt count. Do not keep retrying permanent failures such as a 404 forever. Record the final reason so the operator can requeue selected items later.

Respect the source server. Rate limits and robots or contractual restrictions still apply even when the technical implementation can download faster.

Make the job observable

Expose counts for queued, processing, completed and failed items. Log average download time and recent errors. A long-running job is operational software; it needs visibility just like an API or payment integration.

PUT IT INTO PRACTICE

Turn the idea into a clear implementation plan.

Use TWE to structure requirements first. If you later want implementation, Valron can pick up the same brief.