In Laravel's Process facade, when do you use start(), Process::pool() or Process::pipe() instead of run(), and what does each give back?
answer
- start() returns an InvokedProcess
- running(), wait(), latestOutput()
- pool results keyed, as() names
- concurrently() = start then wait
- pipe stops at first failure
basics
~20 sstart() launches a command in the background and returns an InvokedProcess to poll or wait() on. Process::pool() starts several commands at once and wait() returns their results by key. Process::pipe() feeds each command's output into the next and returns one result.
solid answer
~40 s`run()` blocks until one command ends. `start()` launches it and returns an `InvokedProcess` at once: check `running()`, read `latestOutput()`, send `signal()` or `stop()`, and call `wait()` for the `ProcessResult`; `ensureNotTimedOut()` inside a polling loop surfaces the timeout. `Process::pool(fn (Pool $pool) => ...)` defines several processes, `->start()` launches **all** of them together, and `->wait()` returns a `ProcessPoolResults` indexed by position or by `$pool->as('name')`; `Process::concurrently()` does start and wait in one call. Nothing limits how many pooled processes run at once. `Process::pipe()` runs commands one after another, feeding each one's stdout into the next one's stdin, and returns the last result — or the first failed one, since a failure stops the pipe.
code
php · 20 lines<?php
use Illuminate\Process\Pool;
use Illuminate\Support\Facades\Process;
$sizes = ['small' => '150x150', 'medium' => '600x600', 'large' => '1200x1200'];
$results = Process::concurrently(function (Pool $pool) use ($sizes, $source) {
foreach ($sizes as $name => $geometry) {
$pool->as($name)->timeout(30)->command([
'magick', $source, '-thumbnail', $geometry, storage_path("app/thumbs/{$name}.jpg"),
]);
}
});
foreach ($sizes as $name => $geometry) {
if ($results[$name]->failed()) {
logger()->warning("Thumbnail {$name} failed", ['error' => $results[$name]->errorOutput()]);
}
}go deeper
Remember that run() waits and start() does not, that pool() runs several commands together, and that pipe() chains one command's output into the next.
Explain InvokedProcess methods, how pool results are keyed and aggregated, why concurrently() exists, and how a pipe behaves when a middle stage fails.
Show you control resource use: pools have no cap, started processes need wait() or ensureNotTimedOut(), and heavy batches belong in chunks or queued jobs.
Judge when parallel processes inside one request or job are worth it versus spreading the work across queue workers that you can scale and monitor separately.
## run() versus start() Both methods live on the pending process that the `Process` facade builds, and both accept the same options (`timeout()`, `path()`, `env()`, `input()`). | Method | Blocks? | Returns | Use it for | |---|---|---|---| | `run($cmd)` | yes, until exit | `ProcessResult` | a quick command whose result you need now | | `start($cmd)` | no | `InvokedProcess` | doing other work while the command runs | | `Process::pool($cb)->start()` | no | `InvokedProcessPool` | several independent commands at once | | `Process::concurrently($cb)` | yes, until all exit | `ProcessPoolResults` | the same, when you only need the results | | `Process::pipe($cb or [...])` | yes | `ProcessResult` | chaining stdout of one command into the next | ## Working with a started process `start()` returns an `Illuminate\Process\InvokedProcess` immediately. While it runs you can: - check `running()`; - read `output()` and `errorOutput()` for everything so far, or `latestOutput()` and `latestErrorOutput()` for what arrived since the last read; - get the operating-system process id with `id()`, send a signal with `signal(SIGTERM)`, or `stop()` it; - call `wait()` to block until it ends and receive the `ProcessResult`, or `waitUntil($callback)` to stop waiting once the output matches something, such as a "Ready" line. Timeouts for started processes are raised as `ProcessTimedOutException` from `wait()`, `waitUntil()` or `ensureNotTimedOut()`. That is why the documentation places `ensureNotTimedOut()` inside a `while ($process->running())` loop. Both `run()` and `start()` also accept a closure as their second argument; it receives the output type (`stdout` or `stderr`) and each chunk as it arrives, which is handy for streaming progress into a console command. ## Pools: several processes at once `Process::pool()` takes a closure receiving an `Illuminate\Process\Pool`. Each `$pool->command(...)`, or `$pool->as('small')->timeout(30)->command(...)`, registers a pending process. 1. `->start()` launches **every** registered process at the same moment and returns an `InvokedProcessPool`; its `running()` gives a collection of the processes still alive. 2. `->wait()` waits for each one and returns an `Illuminate\Process\ProcessPoolResults`, which is array-accessible by position or by the `as()` name. 3. `$results->successful()` is true only when every process succeeded; a non-zero exit in one member does not throw, although a member that times out still raises `ProcessTimedOutException` from `wait()`. 4. `Process::concurrently($callback)` is shorthand for pool, start and wait in one call, and pairs well with array destructuring. There is **no concurrency cap**: a pool built from 200 images starts 200 processes. For large batches, split the work into chunks or into queued jobs. ## Pipes `Process::pipe()` accepts either a closure receiving an `Illuminate\Process\Pipe` or a plain array of command strings. It runs the commands **one after another**, handing each command's stdout to the next as stdin, and returns the final `ProcessResult`. If a command in the middle fails, the remaining commands are skipped and **that failed result** is returned, so `failed()` on the pipe's result tells you the chain broke somewhere. `$pipe->as('resize')` names a stage so an output closure can tell stages apart. ## Thumbnails in three sizes A pool fits "make three thumbnail sizes of one upload": the conversions are independent, CPU-heavy, and each can run in its own process. Register one `magick` command per size under `as('small')`, `as('medium')` and `as('large')`, give each its own `timeout()`, call `Process::concurrently()`, and read `$results['small']`, `$results['medium']` and `$results['large']` by name, checking `failed()` and `errorOutput()` on each. ## Choosing between them - One short command whose result decides what happens next: `run()`. - One long command while the PHP code keeps working, reports progress or watches for a "ready" line: `start()` with `latestOutput()` or `waitUntil()`. - Several independent commands that may overlap, such as one conversion per image size: `Process::pool()` or `Process::concurrently()`. - A chain where each command consumes the previous one's output, and you want to know which stage failed: `Process::pipe()`. - Hundreds of commands, or work that must survive a crash: not a pool at all, but queued jobs, so a fixed number of workers bounds the load. ## Pitfalls - Starting a process and never calling `wait()`: you get no result and no timeout exception. - Assuming a pool throttles itself; it starts everything it holds. - Expecting a pool to throw when one member fails — inspect each result or `successful()`. - Using a shell string with `|` when `Process::pipe()` would give you per-stage results without a shell.
- How do you stop a started Laravel process that is taking too long?Keep the `InvokedProcess` from `start()` and call `stop()`, which ends it (with an optional grace period and signal), or `signal(SIGTERM)` to ask it to exit. With a timeout set, calling `ensureNotTimedOut()` while polling raises `ProcessTimedOutException` once the limit passes.
- Why might Process::pipe() return a result from the middle of the chain?The pipe skips the remaining commands as soon as one fails and returns that failed `ProcessResult`. Its `command()`, `exitCode()` and `errorOutput()` tell you which stage broke.
- Does Process::pool() limit how many processes run at the same time?No. `start()` launches every process registered in the pool immediately. To bound CPU use, split the work into several smaller pools or dispatch it as queued jobs processed by a fixed number of workers.
saying these in an interview costs you the question
- start() blocks until the command finishes, just like run().
- Process::pool() runs a few processes at a time and queues the rest.
- A pool throws as soon as any one of its processes fails.
- Process::pipe() runs all its commands at the same time.
- A started process needs no wait() call to report its timeout.