Architecture
May 19, 2026
2 min read
Scheduled Report Generation with Laravel Queues
Design recurring report jobs that stay responsive, avoid duplicates, recover from failures, and deliver private downloads safely.
- Laravel
- Queues
- MySQL

Keep the Request Out of the Report
A report that joins several tables, calculates totals, and exports thousands of rows should not hold a web request open. The user experiences a spinner, a proxy may time out, and repeating the request can start the same expensive work again. A better flow records the requested filters, queues a job, and returns a report request identifier immediately.
In Laravel, a controller can validate the period and filters, create a report record with a pending status, then dispatch a GenerateReport job. Store only the identifiers and normalized parameters in the job rather than a large collection of models. The worker reloads what it needs and can run independently of the browser session.
Schedule and Protect the Work
Use Laravel's scheduler to trigger recurring reports, or schedule a queued job when the work must run on a particular cadence. Put a unique period or run key on each report so retries and duplicate scheduler invocations do not create duplicate deliverables. Scheduler overlap protection is useful, but it should complement application-level idempotency rather than replace it.
The job should update its status through explicit transitions: pending, processing, completed, or failed. If the report depends on a database transaction that creates the source data, dispatch after the transaction commits so a worker cannot read data that is not committed yet. Configure retries for transient failures and set a timeout appropriate to the export size.
Store, Notify, and Expire
Generate the file to private object storage or a protected disk, then save its path and completion time. Avoid placing a permanent public URL in a report row. When the job completes, notify the requesting user with an authenticated download link or a short-lived signed URL. A cleanup task can remove expired files and old report records according to the product's retention policy.
Finally, observe the pipeline. Log the report ID, duration, row count, and failure reason without logging sensitive report contents. Alert on a growing queue or repeated failures, and test empty periods, large exports, duplicate dispatches, and worker restarts. This turns a fragile cron script into a recoverable feature that users can trust.