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

# 프로세스

> Laravel의 Process 파사드를 사용해 외부 셸 명령을 실행하고, 동기·비동기·병렬 처리를 간결하게 다루는 방법을 설명합니다.

## 시작하기

Laravel의 Process 파사드는 [Symfony Process 컴포넌트](https://symfony.com/doc/current/components/process.html)의 얇은 래퍼입니다.
셸 명령을 Laravel 애플리케이션에서 호출하고, 그 결과를 다루기 위한 간결한 API를 제공합니다.

```mermaid theme={null}
flowchart LR
    A["Laravel 앱"] --> B["Process<br>파사드"]
    B --> C["셸 명령"]
    C --> D["ProcessResult<br>(output / exitCode)"]
    D --> A
```

## 프로세스 실행

`Process::run()`을 사용하면 명령을 동기적으로 실행하고 결과를 가져올 수 있습니다.

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

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

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

`ProcessResult` 인스턴스에는 결과를 확인하기 위한 다양한 메서드가 마련되어 있습니다.

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

$result->command();       // 실행한 명령
$result->successful();    // 성공했는지 (종료 코드 0)
$result->failed();        // 실패했는지 (종료 코드 0 이외)
$result->output();        // 표준 출력 (stdout)
$result->errorOutput();   // 표준 에러 출력 (stderr)
$result->exitCode();      // 종료 코드
```

### 실패 시 예외 던지기

종료 코드가 0보다 큰 경우 `Illuminate\Process\Exceptions\ProcessFailedException`을 던지게 하려면 `throw()` 또는 `throwIf()`를 사용합니다.

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

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

## 프로세스 옵션

### 작업 디렉터리

`path()`로 작업 디렉터리를 지정할 수 있습니다. 생략하면 현재 PHP 스크립트의 작업 디렉터리가 사용됩니다.

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

### 표준 입력

`input()`으로 프로세스의 표준 입력에 데이터를 전달할 수 있습니다.

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

### 타임아웃

기본값은 60초입니다. `timeout()`으로 변경할 수 있습니다. 타임아웃이 발생하면 프로세스가 중단되고 `ProcessTimedOutException`이 던져집니다.

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

`CarbonInterval` 헬퍼 함수도 사용할 수 있습니다.

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

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

타임아웃을 무효화하려면 `forever()`를 사용합니다.

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

아이들 타임아웃(출력이 없는 상태가 지속되는 초 수)을 설정할 수도 있습니다.

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

### 환경 변수

`env()`로 환경 변수를 추가하거나 덮어쓸 수 있습니다. 시스템의 환경 변수는 자동으로 상속됩니다.

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

상속된 변수를 제외하려면 `false`를 지정합니다.

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

### 출력 비활성화

대량의 출력이 필요 없는 경우 `quietly()`로 메모리 소비를 억제할 수 있습니다.

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

### 실시간 출력

`run()`의 두 번째 인수에 클로저를 전달하면 출력을 실시간으로 받을 수 있습니다.

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

## 파이프라인

`Process::pipe()`를 사용하면 어떤 명령의 출력을 다음 명령의 입력으로 전달할 수 있습니다.

```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()) {
    // ...
}
```

명령 문자열의 배열을 전달할 수도 있습니다.

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

각 프로세스에 `as()`로 키를 붙이면, 출력 클로저에서 어느 프로세스의 출력인지 구분할 수 있습니다.

```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가 'first' 또는 'second'
});
```

## 비동기 프로세스

`Process::start()`를 사용하면 프로세스를 비동기로 실행할 수 있습니다. 프로세스가 실행 중인 동안 애플리케이션은 다른 처리를 계속할 수 있습니다.

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

while ($process->running()) {
    // 다른 처리
}

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

### 프로세스 ID와 시그널

`id()`로 실행 중인 프로세스의 OS 프로세스 ID를 가져올 수 있습니다.

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

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

`signal()`로 프로세스에 시그널을 보낼 수 있습니다.

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

### 비동기 프로세스의 출력

실행 중에 `latestOutput()`과 `latestErrorOutput()`을 사용하면, 이전 취득 이후의 차분 출력을 가져올 수 있습니다.

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

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

    sleep(1);
}
```

특정 출력이 나타날 때까지 대기하려면 `waitUntil()`을 사용합니다.

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

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

### 비동기 프로세스의 타임아웃 확인

루프 안에서 `ensureNotTimedOut()`을 호출하면, 타임아웃한 경우 예외가 던져집니다.

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

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

    sleep(1);
}
```

## 병렬 프로세스

`Process::pool()`을 사용하면 여러 프로세스를 병렬로 실행할 수 있습니다.

```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();
```

`concurrently()`를 사용하면 풀을 즉시 시작하고 결과를 기다리는 처리를 한 줄로 작성할 수 있습니다.

```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();
```

### 프로세스에 이름 붙이기

`as()`로 각 프로세스에 문자열 키를 붙이면 결과의 취득이 명확해집니다.

```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();
```

풀 전체에 시그널을 보낼 수도 있습니다.

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

## 테스트

### 프로세스 페이크

`Process::fake()`를 사용하면 실제 셸 명령을 실행하지 않고 테스트할 수 있습니다.

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

Process::fake();

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

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

출력이나 종료 코드를 지정할 수도 있습니다.

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

### 특정 명령을 페이크하기

와일드카드나 명령 문자열을 키로 사용해 개별적으로 페이크를 설정할 수 있습니다.

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

### 시퀀스 페이크

같은 명령을 여러 번 호출하는 경우, 반환되는 결과의 순서를 지정할 수 있습니다.

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

### 어서션

| 메서드                                     | 설명                  |
| --------------------------------------- | ------------------- |
| `Process::assertRan('command')`         | 명령이 실행되었음을 검증       |
| `Process::assertNotRan('command')`      | 명령이 실행되지 않았음을 검증    |
| `Process::assertRan(fn)`                | 클로저로 실행 내용을 상세히 검증  |
| `Process::assertRanTimes('command', 3)` | 명령이 지정 횟수 실행되었음을 검증 |

### 예기치 않은 프로세스 방지

`Process::preventStrayProcesses()`를 호출하면 페이크가 설정되지 않은 명령이 실행된 경우 예외가 던져집니다.

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

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

// 예외: 'bash import.sh'에는 페이크가 설정되지 않음
Process::run('bash import.sh');
```

## 관련 페이지

<Columns cols={2}>
  <Card title="Artisan 콘솔" icon="terminal" href="/ko/artisan">
    커스텀 명령을 작성해 프로세스를 호출
  </Card>

  <Card title="큐" icon="list" href="/ko/queues">
    비동기 처리와의 비교
  </Card>
</Columns>


## Related topics

- [WebSocket (Jetstream / Firehose)](/ko/packages/laravel-bluesky/websocket.md)
- [Laravel Reverb](/ko/reverb.md)
- [Labeler](/ko/packages/laravel-bluesky/labeler.md)
- [캐시](/ko/cache.md)
- [TCP 모드](/ko/packages/laravel-copilot-sdk/tcp-mode.md)
