본문 바로가기

프로세스

업데이트됨

번역일: 2026년 8월 19일

이 페이지는 원문이 업데이트되어 번역이 갱신되었습니다.

원문 수정
2026년 8월 19일
번역 갱신
2026년 8월 19일

프로세스

소개

Laravel은 Symfony Process 컴포넌트를 감싸는 간결하고 표현력 있는 API를 제공합니다. 덕분에 애플리케이션에서 외부 프로세스를 편리하게 실행할 수 있습니다. 가장 자주 쓰이는 사용 사례에 집중한 설계로, 뛰어난 개발자 경험을 제공합니다.

프로세스 실행

프로세스를 실행하려면 Process 파사드의 run 또는 start 메서드를 사용합니다. run은 프로세스를 동기적으로 실행하고 완료될 때까지 기다리며, start는 비동기 실행에 사용합니다. 먼저 기본적인 동기 실행 방법을 살펴보겠습니다.

use Illuminate\Support\Facades\Process; $result = Process::run('ls -la'); return $result->output();

run 메서드가 반환하는 Illuminate\Contracts\Process\ProcessResult 인스턴스는 실행 결과를 검사할 수 있는 다양한 메서드를 제공합니다.

$result = Process::run('ls -la'); $result->command(); // 실행한 명령어 $result->successful(); // 성공 여부 $result->failed(); // 실패 여부 $result->output(); // 표준 출력 (stdout) $result->errorOutput(); // 오류 출력 (stderr) $result->exitCode(); // 종료 코드

예외 발생시키기

프로세스가 실패(종료 코드가 0보다 큰 경우)했을 때 Illuminate\Process\Exceptions\ProcessFailedException 예외를 발생시키려면 throw 또는 throwIf 메서드를 사용하세요. 프로세스가 실패하지 않은 경우에는 ProcessResult 인스턴스가 그대로 반환됩니다.

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

프로세스 옵션

프로세스를 실행하기 전에 작업 디렉터리, 타임아웃, 환경 변수 등 다양한 동작을 커스터마이즈할 수 있습니다.

작업 디렉터리 지정

path 메서드로 프로세스의 작업 디렉터리를 지정합니다. 지정하지 않으면 현재 PHP 스크립트의 작업 디렉터리를 그대로 상속합니다.

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

표준 입력

input 메서드를 사용하면 프로세스의 표준 입력(stdin)으로 데이터를 전달할 수 있습니다.

$result = Process::input('Hello World')->run('cat');

타임아웃

기본적으로 프로세스가 60초를 초과하면 Illuminate\Process\Exceptions\ProcessTimedOutException이 발생합니다. timeout 메서드로 이 값을 변경할 수 있습니다.

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

timeoutidleTimeout 메서드는 CarbonInterval 인스턴스도 받을 수 있습니다.

use function Illuminate\Support\minutes; $result = Process::timeout(minutes(2))->run('bash import.sh');

타임아웃을 완전히 비활성화하려면 forever 메서드를 사용하세요.

$result = Process::forever()->run('bash import.sh');

idleTimeout은 프로세스가 출력 없이 실행될 수 있는 최대 시간을 지정합니다. 아래 예시는 전체 실행 시간 60초, 무출력 허용 시간 30초를 설정합니다.

$result = Process::timeout(60)->idleTimeout(30)->run('bash import.sh');

환경 변수

env 메서드로 프로세스에 환경 변수를 전달할 수 있습니다. 실행되는 프로세스는 시스템에 정의된 환경 변수도 함께 상속합니다.

$result = Process::forever() ->env(['IMPORT_PATH' => __DIR__]) ->run('bash import.sh');

상속된 환경 변수를 제거하려면 해당 변수의 값을 false로 지정하세요.

$result = Process::forever() ->env(['LOAD_PATH' => false]) ->run('bash import.sh');

TTY 모드

tty 메서드를 사용하면 TTY 모드를 활성화할 수 있습니다. TTY 모드는 프로세스의 입출력을 현재 프로그램의 입출력에 연결하므로, Vim이나 Nano 같은 인터랙티브 에디터를 프로세스로 열 때 활용할 수 있습니다.

Process::forever()->tty()->run('vim');

WARNING

TTY 모드는 Windows에서 지원되지 않습니다.

프로세스 출력

앞서 설명한 것처럼, 프로세스 결과에서 output(stdout)과 errorOutput(stderr) 메서드로 출력을 가져올 수 있습니다.

use Illuminate\Support\Facades\Process; $result = Process::run('ls -la'); echo $result->output(); echo $result->errorOutput();

출력을 실시간으로 처리하려면 run 메서드의 두 번째 인자로 클로저를 전달하세요. 클로저는 출력 타입(stdout 또는 stderr)과 출력 문자열을 인자로 받습니다.

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

특정 문자열이 출력에 포함되어 있는지 확인할 때는 seeInOutputseeInErrorOutput을 사용하세요.

if (Process::run('ls -la')->seeInOutput('laravel')) { // ... }

프로세스 출력 비활성화

출력 내용이 많지만 실제로 필요하지 않은 경우, quietly 메서드로 출력 수집 자체를 비활성화하여 메모리를 절약할 수 있습니다.

use Illuminate\Support\Facades\Process; $result = Process::quietly()->run('bash import.sh');

파이프라인

한 프로세스의 출력을 다른 프로세스의 입력으로 연결하고 싶을 때는 pipe 메서드를 사용합니다. 파이프라인의 프로세스들은 동기적으로 실행되며, 마지막 프로세스의 결과가 반환됩니다.

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

개별 프로세스를 커스터마이즈할 필요가 없다면 명령어 문자열 배열을 바로 전달할 수도 있습니다.

$result = Process::pipe([ 'cat example.txt', 'grep -i "laravel"', ]);

파이프라인의 출력도 실시간으로 처리할 수 있습니다. 클로저는 출력 타입, 출력 문자열, 그리고 어떤 프로세스에서 나온 출력인지를 나타내는 키를 인자로 받습니다.

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

as 메서드로 파이프라인 내 각 프로세스에 문자열 키를 지정하면, 출력 클로저에서 해당 키로 어느 프로세스의 출력인지 식별할 수 있습니다.

$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로 어느 프로세스의 출력인지 확인 });

비동기 프로세스

run 메서드가 동기 방식인 반면, start 메서드는 프로세스를 비동기로 실행합니다. 프로세스가 백그라운드에서 실행되는 동안 애플리케이션은 다른 작업을 계속 수행할 수 있습니다. running 메서드로 프로세스가 아직 실행 중인지 확인할 수 있습니다.

$process = Process::timeout(120)->start('bash import.sh'); while ($process->running()) { // 다른 작업 수행 가능 } $result = $process->wait();

wait 메서드는 프로세스가 완료될 때까지 기다렸다가 ProcessResult 인스턴스를 반환합니다.

$process = Process::timeout(120)->start('bash import.sh'); // ... 다른 작업 수행 $result = $process->wait();

프로세스 ID와 시그널

id 메서드로 운영체제가 할당한 프로세스 ID를 가져올 수 있습니다.

$process = Process::start('bash import.sh'); return $process->id();

signal 메서드로 실행 중인 프로세스에 시그널을 보낼 수 있습니다. 사용 가능한 시그널 상수 목록은 PHP 문서를 참고하세요.

$process->signal(SIGUSR2);

비동기 프로세스 출력

비동기 프로세스가 실행되는 동안 outputerrorOutput으로 지금까지 쌓인 전체 출력을 가져올 수 있습니다. 마지막으로 읽은 이후에 새로 생성된 출력만 가져오려면 latestOutputlatestErrorOutput을 사용하세요.

$process = Process::timeout(120)->start('bash import.sh'); while ($process->running()) { echo $process->latestOutput(); echo $process->latestErrorOutput(); sleep(1); }

start 메서드의 두 번째 인자로 클로저를 전달하면 비동기 프로세스에서도 출력을 실시간으로 처리할 수 있습니다.

$process = Process::start('bash import.sh', function (string $type, string $output) { echo $output; }); $result = $process->wait();

프로세스가 완전히 종료되길 기다리는 대신, 특정 출력이 나타날 때 대기를 중단하고 싶다면 waitUntil 메서드를 사용하세요. 클로저가 true를 반환하는 순간 대기가 중단됩니다.

$process = Process::start('bash import.sh'); $process->waitUntil(function (string $type, string $output) { return $output === 'Ready...'; });

비동기 프로세스 타임아웃

비동기 프로세스가 실행 중인 루프 안에서 ensureNotTimedOut 메서드를 호출하면, 타임아웃이 발생했을 때 즉시 타임아웃 예외를 발생시킬 수 있습니다.

$process = Process::timeout(120)->start('bash import.sh'); while ($process->running()) { $process->ensureNotTimedOut(); // ... sleep(1); }

동시 프로세스

Laravel은 여러 비동기 프로세스를 풀(pool)로 묶어 동시에 실행하는 기능도 제공합니다. pool 메서드에 클로저를 전달하면 Illuminate\Process\Pool 인스턴스를 통해 풀에 포함할 프로세스들을 정의할 수 있습니다.

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

wait 메서드는 모든 프로세스가 완료된 후 결과를 반환합니다. 각 프로세스의 결과는 풀에서의 키(인덱스)로 접근할 수 있습니다.

$results = $pool->wait(); echo $results[0]->output();

concurrently 메서드를 사용하면 풀을 시작하고 결과를 즉시 기다리는 과정을 한 번에 처리할 수 있습니다. PHP의 배열 구조 분해와 함께 사용하면 더욱 간결한 코드를 작성할 수 있습니다.

[$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 메서드로 각 프로세스에 문자열 키를 지정하면, 결과 접근과 출력 식별이 훨씬 명확해집니다.

$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) { // $key로 어느 프로세스의 출력인지 식별 }); $results = $pool->wait(); return $results['first']->output();

풀 프로세스 ID와 시그널

running 메서드는 풀에서 실행 중인 모든 프로세스의 컬렉션을 반환하므로, 각 프로세스의 ID를 쉽게 수집할 수 있습니다.

$processIds = $pool->running()->each->id();

풀 전체에 시그널을 보내려면 프로세스 풀 인스턴스에서 직접 signal 메서드를 호출하세요.

$pool->signal(SIGUSR2);

테스트

Laravel의 프로세스 서비스도 다른 서비스들과 마찬가지로 테스트를 쉽게 작성할 수 있도록 지원합니다. Process 파사드의 fake 메서드를 사용하면 실제 프로세스를 실행하지 않고 미리 정의한 가짜 결과를 반환하도록 설정할 수 있습니다.

프로세스 페이킹

프로세스를 실행하는 라우트를 예시로 살펴보겠습니다.

use Illuminate\Support\Facades\Process; use Illuminate\Support\Facades\Route; Route::get('/import', function () { Process::run('bash import.sh'); return 'Import complete!'; });

이 라우트를 테스트할 때 Process::fake()를 인자 없이 호출하면, 이후 실행되는 모든 프로세스가 성공 결과를 반환하는 가짜 프로세스로 대체됩니다. 또한 특정 프로세스가 실제로 실행됐는지 어설션으로 검증할 수 있습니다.

Pest

<?php use Illuminate\Contracts\Process\ProcessResult; use Illuminate\Process\PendingProcess; use Illuminate\Support\Facades\Process; test('process is invoked', function () { Process::fake(); $response = $this->get('/import'); // 단순 실행 여부 어설션 Process::assertRan('bash import.sh'); // 프로세스 설정값 검사 Process::assertRan(function (PendingProcess $process, ProcessResult $result) { return $process->command === 'bash import.sh' && $process->timeout === 60; }); });

PHPUnit

<?php namespace Tests\Feature; use Illuminate\Contracts\Process\ProcessResult; use Illuminate\Process\PendingProcess; use Illuminate\Support\Facades\Process; use Tests\TestCase; class ExampleTest extends TestCase { public function test_process_is_invoked(): void { Process::fake(); $response = $this->get('/import'); // 단순 실행 여부 어설션 Process::assertRan('bash import.sh'); // 프로세스 설정값 검사 Process::assertRan(function (PendingProcess $process, ProcessResult $result) { return $process->command === 'bash import.sh' && $process->timeout === 60; }); } }

fake 메서드를 인자 없이 호출하면 기본적으로 출력이 없는 성공 결과가 반환됩니다. 출력 내용이나 종료 코드를 지정하려면 result 메서드를 사용하세요.

Process::fake([ '*' => Process::result( output: '테스트 출력', errorOutput: '테스트 오류 출력', exitCode: 1, ), ]);

특정 프로세스 페이킹

fake 메서드에 배열을 전달하면 명령어 패턴별로 다른 가짜 결과를 지정할 수 있습니다. 배열의 키는 명령어 패턴이며 *를 와일드카드로 사용할 수 있습니다. 배열에 정의되지 않은 명령어는 실제로 실행됩니다.

Process::fake([ 'cat *' => Process::result( output: '"cat" 명령어 테스트 출력', ), 'ls *' => Process::result( output: '"ls" 명령어 테스트 출력', ), ]);

종료 코드나 오류 출력을 따로 지정할 필요가 없다면 문자열로 간단히 지정할 수도 있습니다.

Process::fake([ 'cat *' => '"cat" 명령어 테스트 출력', 'ls *' => '"ls" 명령어 테스트 출력', ]);

프로세스 시퀀스 페이킹

같은 명령어를 여러 번 호출할 때 각 호출마다 다른 결과를 반환하게 하려면 sequence 메서드를 사용하세요.

Process::fake([ 'ls *' => Process::sequence() ->push(Process::result('첫 번째 호출 결과')) ->push(Process::result('두 번째 호출 결과')), ]);

비동기 프로세스 라이프사이클 페이킹

비동기 프로세스(start로 실행)를 테스트할 때는 running 메서드가 몇 번 true를 반환할지, 출력이 어떤 순서로 나올지를 세밀하게 제어해야 합니다. 이럴 때는 describe 메서드를 사용합니다.

아래 라우트를 테스트한다고 가정해 보겠습니다.

use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Route; Route::get('/import', function () { $process = Process::start('bash import.sh'); while ($process->running()) { Log::info($process->latestOutput()); Log::info($process->latestErrorOutput()); } return 'Done'; });

describe 메서드로 이 비동기 프로세스의 동작을 상세히 정의할 수 있습니다.

Process::fake([ 'bash import.sh' => Process::describe() ->output('표준 출력 첫 번째 줄') ->errorOutput('오류 출력 첫 번째 줄') ->output('표준 출력 두 번째 줄') ->exitCode(0) ->iterations(3), ]);
  • output / errorOutput: 순서대로 반환될 출력 줄을 지정합니다.
  • exitCode: 프로세스 종료 시 반환할 종료 코드를 지정합니다.
  • iterations: running 메서드가 true를 반환할 횟수를 지정합니다.

사용 가능한 어설션

앞서 설명한 것처럼 Laravel은 기능 테스트에서 사용할 수 있는 다양한 프로세스 어설션을 제공합니다.

assertRan

특정 프로세스가 실행됐는지 검증합니다.

use Illuminate\Support\Facades\Process; Process::assertRan('ls -la');

명령어를 배열 형태로 전달하여 검증할 수도 있습니다.

Process::assertRan(['php', 'artisan', 'migrate']);

NOTE

assertRanTimesassertDidntRun도 배열 형태의 명령어를 지원합니다.

클로저를 전달하면 프로세스의 설정값을 직접 검사할 수 있습니다. 클로저가 true를 반환하면 어설션이 통과합니다.

Process::assertRan(fn ($process, $result) => $process->command === 'ls -la' && $process->path === __DIR__ && $process->timeout === 60 );

클로저의 $processIlluminate\Process\PendingProcess 인스턴스이고, $resultIlluminate\Contracts\Process\ProcessResult 인스턴스입니다.

assertDidntRun

특정 프로세스가 실행되지 않았는지 검증합니다.

use Illuminate\Support\Facades\Process; Process::assertDidntRun('ls -la');

클로저를 전달하면 해당 클로저가 true를 반환할 때 어설션이 실패합니다.

Process::assertDidntRun(fn (PendingProcess $process, ProcessResult $result) => $process->command === 'ls -la' );

assertRanTimes

특정 프로세스가 지정한 횟수만큼 실행됐는지 검증합니다.

use Illuminate\Support\Facades\Process; Process::assertRanTimes('ls -la', times: 3);

클로저를 전달하면 클로저가 true를 반환하는 실행이 지정한 횟수와 일치할 때 어설션이 통과합니다.

Process::assertRanTimes(function (PendingProcess $process, ProcessResult $result) { return $process->command === 'ls -la'; }, times: 3);

assertRanInOrder

프로세스들이 지정한 순서대로 실행됐는지 검증합니다.

Process::assertRanInOrder([ 'git fetch', 'composer install', ]);

다른 프로세스 어설션과 마찬가지로 명령어 문자열, 배열, 클로저를 모두 사용할 수 있습니다.

실제 프로세스 실행 방지

테스트 중에 페이킹되지 않은 프로세스가 실제로 실행되는 것을 막고 싶다면 preventStrayProcesses 메서드를 사용하세요. 이 메서드를 호출하면 가짜 결과가 정의되지 않은 프로세스를 실행하려 할 때 예외가 발생합니다.

use Illuminate\Support\Facades\Process; Process::preventStrayProcesses(); Process::fake([ 'ls *' => '테스트 출력...', ]); // 가짜 결과 반환 (정상) Process::run('ls -la'); // 예외 발생! (페이킹 미정의) Process::run('bash import.sh');

이 문서는 Laravel 공식 문서(MIT)를 한국 개발자를 위해 번역·재구성한 것입니다.

번역일: 2026년 8월 19일