Architecture: Laravel-Centric Asynchronous Processing
The core principle remains the same: decouple the heavy lifting from the web request. The only change is that the “worker” is now a Laravel process itself.Visual Flow Diagram
Detailed Step-by-Step Flow (Laravel Queue & Worker)
Step 1: Document Upload and Job Dispatch (Controller)
This part is nearly identical, but becomes even simpler.- User Uploads PDF: A user submits a form with the PDF.
- Initial Record & Storage: Your
DocumentControllerdoes the following:
- Validates the request.
- Creates a
Documentrecord in your database withstatus = 'pending'. - Uploads the file to a shared storage (S3, Supabase Storage, etc.).
- Updates the
Documentrecord with thestorage_path.
- Dispatch the Job: This is where Laravel’s elegance shines. You create a dedicated Job class and dispatch it.
php artisan make:job ProcessDocumentJob.
Step 2: The Processing Pipeline (The Laravel Job)
All the complex logic now lives inside thehandle() method of your App\Jobs\ProcessDocumentJob.php file. The worker is a long-running process started on your server via php artisan queue:work.
Here is a skeleton of what your Job class would look like:
Pros and Cons of this Approach
Pros (Advantages)
- Unified Codebase & Simplicity: Your entire application logic lives in one place. No need to manage, test, and deploy a separate service in a different language.
- Developer Experience: It’s pure Laravel. You use tools you already know: Eloquent, the
Httpclient, Jobs, Queues, etc. - Seamless Model Access: The job gets the actual
DocumentEloquent model. Updating status is as simple as$this->document->update([...]). There is no need for internal API calls/webhooks between services. - Built-in Error Handling: Laravel’s queue system has robust, built-in support for retries, timeouts, and a
failed_jobstable for easy inspection. - Simplified Deployment: You deploy one application. To scale the processing, you just run more
php artisan queue:workprocesses on one or more servers.
Cons (The “Less Optimal” Aspects)
- Language Ecosystem: Python has a richer ecosystem for data science, machine learning, and AI tasks (e.g., libraries for generating embeddings locally). In PHP, you will almost always rely on calling external APIs for these tasks.
- Resource Management: If you run your queue workers on the same server as your web server (e.g., Forge, Ploi default setup), a very intensive job could potentially impact web request performance. The solution is to run workers on separate, dedicated servers, which is a common scaling pattern.
- Single Point of Failure: If your Laravel app goes down, both the web front-end and the processing back-end go down. (This is true for any monolith).
Conclusion: The Recommended Path
For your use case, using the Laravel Queue with an Artisan worker is the optimal choice to start with. The benefits of simplicity, speed of development, and maintainability are immense. The performance of this entire flow is dictated by the external APIs (docling, embedding API) and database writes, not by the execution speed of PHP. Therefore, the “cons” are largely academic until you reach a massive scale where a microservice architecture might become necessary.
To get this running in production, you will need:
- Configure your queue driver to
redisin.env. - Install a process manager like Supervisor on your server to run
php artisan queue:workand ensure it stays running.
