> ## Documentation Index
> Fetch the complete documentation index at: https://kawax.biz/llms.txt
> Use this file to discover all available pages before exploring further.

# Procesos

> Aprende a ejecutar comandos de shell externos con el facade Process de Laravel, gestionando de forma sencilla llamadas síncronas, asíncronas y concurrentes.

## Introducción

El facade `Process` de Laravel es un envoltorio ligero sobre el [componente Process de Symfony](https://symfony.com/doc/current/components/process.html).
Ofrece una API concisa para ejecutar comandos de shell desde tu aplicación Laravel y tratar el resultado.

```mermaid theme={null}
flowchart LR
    A["Aplicación Laravel"] --> B["Facade<br>Process"]
    B --> C["Comando de shell"]
    C --> D["ProcessResult<br>(output / exitCode)"]
    D --> A
```

## Arrancar un proceso

Con `Process::run()` ejecutas un comando de forma síncrona y obtienes el resultado.

```php theme={null}
use Illuminate\Support\Facades\Process;

$result = Process::run('ls -la');

return $result->output();
```

La instancia `ProcessResult` expone métodos para inspeccionar el resultado.

```php theme={null}
$result = Process::run('ls -la');

$result->command();       // Comando ejecutado
$result->successful();    // ¿Éxito? (código 0)
$result->failed();        // ¿Fallo? (código distinto de 0)
$result->output();        // Salida estándar (stdout)
$result->errorOutput();   // Salida de error (stderr)
$result->exitCode();      // Código de salida
```

### Lanzar una excepción si falla

Para lanzar `Illuminate\Process\Exceptions\ProcessFailedException` cuando el código sea superior a 0, utiliza `throw()` o `throwIf()`.

```php theme={null}
$result = Process::run('ls -la')->throw();

$result = Process::run('ls -la')->throwIf($condition);
```

## Opciones del proceso

### Directorio de trabajo

Indica el directorio con `path()`. Si lo omites, se utiliza el directorio actual del script PHP.

```php theme={null}
$result = Process::path(__DIR__)->run('ls -la');
```

### Entrada estándar

Con `input()` pasas datos por la entrada estándar del proceso.

```php theme={null}
$result = Process::input('Hello World')->run('cat');
```

### Timeout

Por defecto son 60 segundos. Cámbialo con `timeout()`. Si expira, el proceso se aborta y se lanza `ProcessTimedOutException`.

```php theme={null}
$result = Process::timeout(120)->run('bash import.sh');
```

También puedes usar helpers `CarbonInterval`.

```php theme={null}
use function Illuminate\Support\minutes;

$result = Process::timeout(minutes(2))->run('bash import.sh');
```

Para desactivar el timeout utiliza `forever()`.

```php theme={null}
$result = Process::forever()->run('bash import.sh');
```

También hay un idle timeout (segundos consecutivos sin salida).

```php theme={null}
$result = Process::timeout(60)->idleTimeout(30)->run('bash import.sh');
```

### Variables de entorno

Con `env()` añades o sobrescribes variables de entorno. Las del sistema se heredan automáticamente.

```php theme={null}
$result = Process::forever()
    ->env(['IMPORT_PATH' => __DIR__])
    ->run('bash import.sh');
```

Para excluir una variable heredada, asígnale `false`.

```php theme={null}
$result = Process::forever()
    ->env(['LOAD_PATH' => false])
    ->run('bash import.sh');
```

### Desactivar la salida

Si no vas a usar salidas voluminosas, `quietly()` reduce el consumo de memoria.

```php theme={null}
$result = Process::quietly()->run('bash import.sh');
```

### Salida en tiempo real

Pasando una closure como segundo argumento de `run()`, recibes la salida en streaming.

```php theme={null}
$result = Process::run('ls -la', function (string $type, string $output) {
    echo $output;
});
```

## Pipelines

Con `Process::pipe()` la salida de un comando alimenta la entrada del siguiente.

```php theme={null}
use Illuminate\Process\Pipe;
use Illuminate\Support\Facades\Process;

$result = Process::pipe(function (Pipe $pipe) {
    $pipe->command('cat example.txt');
    $pipe->command('grep -i "laravel"');
});

if ($result->successful()) {
    // ...
}
```

También puedes pasar un array de comandos.

```php theme={null}
$result = Process::pipe([
    'cat example.txt',
    'grep -i "laravel"',
]);
```

Si asignas una clave con `as()` a cada proceso, la closure de salida puede identificar de cuál proviene la salida.

```php theme={null}
$result = Process::pipe(function (Pipe $pipe) {
    $pipe->as('first')->command('cat example.txt');
    $pipe->as('second')->command('grep -i "laravel"');
}, function (string $type, string $output, string $key) {
    // $key vale 'first' o 'second'
});
```

## Procesos asíncronos

Con `Process::start()` arrancas un proceso en segundo plano. Tu aplicación puede seguir con otras tareas mientras se ejecuta.

```php theme={null}
$process = Process::timeout(120)->start('bash import.sh');

while ($process->running()) {
    // Otras tareas
}

$result = $process->wait();
```

### PID y señales

Con `id()` obtienes el PID del proceso.

```php theme={null}
$process = Process::start('bash import.sh');

return $process->id();
```

Con `signal()` envías una señal al proceso.

```php theme={null}
$process->signal(SIGUSR2);
```

### Salida de un proceso asíncrono

Durante la ejecución, `latestOutput()` y `latestErrorOutput()` devuelven la salida generada desde la última llamada.

```php theme={null}
$process = Process::timeout(120)->start('bash import.sh');

while ($process->running()) {
    echo $process->latestOutput();
    echo $process->latestErrorOutput();

    sleep(1);
}
```

Para esperar hasta que aparezca una determinada salida utiliza `waitUntil()`.

```php theme={null}
$process = Process::start('bash import.sh');

$process->waitUntil(function (string $type, string $output) {
    return $output === 'Ready...';
});
```

### Comprobar timeouts en asíncrono

Llamar a `ensureNotTimedOut()` dentro del bucle lanza una excepción si el proceso ha excedido el timeout.

```php theme={null}
$process = Process::timeout(120)->start('bash import.sh');

while ($process->running()) {
    $process->ensureNotTimedOut();

    sleep(1);
}
```

## Procesos concurrentes

Con `Process::pool()` ejecutas varios procesos en paralelo.

```php theme={null}
use Illuminate\Process\Pool;
use Illuminate\Support\Facades\Process;

$pool = Process::pool(function (Pool $pool) {
    $pool->path(__DIR__)->command('bash import-1.sh');
    $pool->path(__DIR__)->command('bash import-2.sh');
    $pool->path(__DIR__)->command('bash import-3.sh');
})->start(function (string $type, string $output, int $key) {
    // ...
});

while ($pool->running()->isNotEmpty()) {
    // ...
}

$results = $pool->wait();
```

Con `concurrently()` arrancas el pool y esperas los resultados en una sola línea.

```php theme={null}
[$first, $second, $third] = Process::concurrently(function (Pool $pool) {
    $pool->path(__DIR__)->command('ls -la');
    $pool->path(app_path())->command('ls -la');
    $pool->path(storage_path())->command('ls -la');
});

echo $first->output();
```

### Asignar nombres a los procesos

Con `as()` asignas una clave a cada proceso para acceder cómodamente al resultado.

```php theme={null}
$pool = Process::pool(function (Pool $pool) {
    $pool->as('first')->command('bash import-1.sh');
    $pool->as('second')->command('bash import-2.sh');
    $pool->as('third')->command('bash import-3.sh');
})->start(function (string $type, string $output, string $key) {
    // ...
});

$results = $pool->wait();

return $results['first']->output();
```

También puedes enviar una señal a todo el pool.

```php theme={null}
$pool->signal(SIGUSR2);
```

## Pruebas

### Fake de procesos

Con `Process::fake()` puedes escribir tests sin ejecutar comandos reales.

```php theme={null}
use Illuminate\Support\Facades\Process;

Process::fake();

$response = $this->get('/import');

Process::assertRan('bash import.sh');
```

Puedes especificar la salida y el código de salida.

```php theme={null}
Process::fake([
    '*' => Process::result(
        output: 'Test output',
        errorOutput: 'Test error output',
        exitCode: 1,
    ),
]);
```

### Fake de comandos concretos

Con comodines o cadenas exactas como clave, puedes definir fakes distintos.

```php theme={null}
Process::fake([
    'cat *'    => Process::result(output: 'file contents'),
    'ls -la'   => Process::result(output: 'file listing'),
]);
```

### Fakes en secuencia

Cuando se invoca varias veces el mismo comando, puedes definir el orden de las respuestas.

```php theme={null}
Process::fake([
    'ls *' => [
        Process::result('first time'),
        Process::result('second time'),
    ],
]);
```

### Aserciones

| Método                                  | Descripción                            |
| --------------------------------------- | -------------------------------------- |
| `Process::assertRan('command')`         | Verifica que se ejecutó el comando     |
| `Process::assertNotRan('command')`      | Verifica que no se ejecutó             |
| `Process::assertRan(fn)`                | Validación detallada con closure       |
| `Process::assertRanTimes('command', 3)` | Se ejecutó el número indicado de veces |

### Prevenir procesos no simulados

Al llamar a `Process::preventStrayProcesses()`, si se ejecuta un comando sin fake definido se lanza una excepción.

```php theme={null}
Process::preventStrayProcesses();

Process::fake([
    'ls *' => Process::result('file listing'),
]);

// Excepción: 'bash import.sh' no tiene fake
Process::run('bash import.sh');
```

## Páginas relacionadas

<Columns cols={2}>
  <Card title="Consola Artisan" icon="terminal" href="/es/artisan">
    Crea comandos personalizados que invoquen procesos.
  </Card>

  <Card title="Colas" icon="list" href="/es/queues">
    Compáralo con el procesamiento asíncrono.
  </Card>
</Columns>


## Related topics

- [WebSocket (Jetstream / Firehose)](/es/packages/laravel-bluesky/websocket.md)
- [Laravel Reverb](/es/reverb.md)
- [Labeler](/es/packages/laravel-bluesky/labeler.md)
- [Estructura de aplicación en Laravel 11 y posteriores](/es/advanced/app-structure.md)
- [Modo TCP](/es/packages/laravel-copilot-sdk/tcp-mode.md)
