Deploying AI-Powered Laravel Apps: Queues, Streaming, Timeouts
Why LLM Calls Break Your Server's Defaults
Your stack was tuned for short requests. Every layer between the browser and the LLM API has a timeout or a buffer, and nearly all of them are wrong for AI workloads:
| Layer | Default | Why it breaks |
|---|---|---|
PHP max_execution_time |
30 seconds | A 45-second completion dies mid-request |
Nginx fastcgi_read_timeout |
60 seconds | Nginx returns a 504 while the model is still thinking |
| Nginx FastCGI buffering | On | Streamed tokens sit in a buffer; the user sees nothing, then everything |
| Laravel HTTP client | 30 seconds | Long completions throw ConnectionException |
Queue retry_after |
90 seconds | A 2-minute job gets handed to a second worker and billed twice |
That last row is the expensive one, and we'll spend a whole section on it. But first, the rule that prevents most of these problems from mattering at all.
Rule #1: LLM Calls Belong in Queued Jobs
Never make an LLM call inside a web request if you can possibly avoid it. A synchronous call ties up a PHP-FPM worker for the full duration of the completion. With the default pm.max_children on a small VPS, a dozen users triggering AI features simultaneously can exhaust your entire FPM pool, and now your login page is timing out because your summarizer is slow.
Queued jobs fix the architecture. The web request dispatches a job and returns in milliseconds. A dedicated worker makes the slow call. The result comes back to the user via polling, broadcasting, or a stream (more on that below).
Here's a job skeleton with every LLM-specific concern handled:
// Job skeleton code goes here
Comments
No comments yet. Start the discussion.