Lang x Lang

Processes

Table of Contents

Introduction

Laravel は、表現豊かで最小限の API をSymfony の Processcomponent を中心に提供し、外部 processes をあなたの Laravel アプリケーションから便利に呼び出せるようにします。Laravel の processes 機能は、最も一般的な使用ケースと素晴らしい development 者体験に焦点を当てています。

Invoking Processes

Process facade が提供する run および start メソッドを使うと、 process を起動できます。run method は、 process を起動し、その process が終了するのを待ちます。一方、start method は非同期の process の実行に使用されます。このドキュメンテーション内で両方のアプローチについて調査します。まず、基本的な同期的な process を呼び出し、その結果を調査する方法を見てみましょう。

use Illuminate\Support\Facades\Process;

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

return $result->output();

もちろん、run method によって返されるIlluminate\Contracts\Process\ProcessResultインスタンスは、 process の結果を調査するために使用できる多種多様な便利なメソッドを提供します:

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

$result->successful();
$result->failed();
$result->exitCode();
$result->output();
$result->errorOutput();

Throwing Exceptions

もし process の結果があり、終了 code がゼロより大きい(つまり、失敗を示す)場合に Illuminate\Process\Exceptions\ProcessFailedException のインスタンスを throw したい場合は、throw および throwIf メソッドを使用できます。もし process が失敗していない場合、 process の結果のインスタンスが返されます:

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

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

Process Options

もちろん、 process を呼び出す前にその挙動をカスタマイズする必要があるかもしれません。幸いなことに、 Laravel は作業ディレクトリや、 timeout 、 environment 変数など、さまざまな process features を微調整することを可能にします。

ワーキングディレクトリ Path

path method を使用して、 process の作業ディレクトリを指定することができます。この method が呼び出されない場合、 process は現在実行中の PHPscripts の作業ディレクトリを継承します。

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

Input

あなたはinputの method を使用して、"standard input"を介して process に input を提供することができます:

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

Timeouts

default では、プロセスは 60 秒以上実行した後にIlluminate\Process\Exceptions\ProcessTimedOutExceptionのインスタンスを throw します。しかし、timeout method を使ってこの挙動をカスタマイズすることができます:

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

または、 process timeout を完全に無効にしたい場合は、forever method を呼び出すことができます:

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

idleTimeoutの method は、 process が何も output を返さずに実行できる最大秒数を指定するために使用することができます:

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

Environment 変数

Environment 変数は、env method を介して process に提供することができます。呼び出された process は、システムで定義されたすべての environment 変数を継承します:

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

falseの value を提供して、呼び出された process から継承された environment variables を削除したい場合があります。

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

TTY モード

tty method は、process に TTY モードを有効にするために使用できます。TTY モードは、process の input および output をプログラムの input および output に接続し、Vim や Nano などのエディタを process として開くことを可能にします:

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

Process Output

以前に議論したように、 process output は、 process 結果の output ( stdout ) メソッドと errorOutput ( stderr ) メソッドを使用してアクセスすることができます。

use Illuminate\Support\Facades\Process;

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

echo $result->output();
echo $result->errorOutput();

ただし、run の method に二つ目の引数としてクロージャを渡すことで、 output はリアルタイムで収集することも可能です。そのクロージャは二つの引数( output の "type" (stdout または stderr)および output string 自体)を受け取ります。

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

Laravel はまた、seeInOutputseeInErrorOutputメソッドも提供します。これらは、特定の string がプロセスの output に含まれていたかどうかを判断する便利な方法を提供します:

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

Process Output の無効化

あなたの process が興味のない大量の output を書き出している場合は、 output の取得を完全に無効化することでメモリを節約できます。これを実現するためには、 process を構築する際にquietly method を呼び出します:

use Illuminate\Support\Facades\Process;

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

Pipelines

時には、ある process の output を別の process の input にすることが望ましいかもしれません。これは通常、ある process の output を別のものに"パイピング"するといいます。Process facades が提供するpipe method を使えば、これを簡単に達成することができます。pipe method は pipeline 化された process を同期的に実行し、pipeline 内の最後の process の結果を返します。

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

もし pipeline を構成する個々の processes をカスタマイズする必要がない場合、シンプルにpipe method に command strings の array を渡すことができます:

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

process output は、pipe method に 2 つ目の引数としてクロージャを渡すことでリアルタイムで収集できます。クロージャは 2 つの引数を受け取ります: output の型(stdoutまたはstderr)と output string 自体:

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

Laravel は、as method を介して、各 process に string keys を割り当てることも可能です。この keys はpipe method で提供される output クロージャにも渡され、どの process が output に属しているかを判断することができます。

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

Asynchronous Processes

runの method はプロセスを同期的に呼び出しますが、startの method は process を非同期的に呼び出すために使用できます。これにより、 application が他のタスクを続けながら process がバックグラウンドで実行されることが可能になります。 process が呼び出された後、runningの method を活用して process がまだ実行中であるかどうかを判断することができます:

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

while ($process->running()) {
    // ...
}

$result = $process->wait();

ご覧の通り、wait method を呼び出し、 process が実行を終了するのを待ち、 process の結果インスタンスを取得することができます。

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

// ...

$result = $process->wait();

Process ID とシグナル

id method は、実行中の process のオペレーティングシステムによって割り当てられた process ID を取得するために使用できます:

$process = Process::start('bash import.sh');

return $process->id();

signal method を使用して、実行中の process に "signal" を送信できます。定義済みのシグナル定数の一覧は PHP documentation にあります。

$process->signal(SIGUSR2);

非同期の Process Output

非同期の process が実行中の場合、その現在の全ての output をoutputおよびerrorOutputメソッドを使用してアクセスすることができます。しかし、最後に output が retrieved されてからの process からの output にアクセスするためには、latestOutputおよびlatestErrorOutputを利用することができます。

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

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

    sleep(1);
}

run method のように、出力も非同期 processes からリアルタイムで収集することができます。これは、start method の 2 つ目の引数にクロージャを渡すことで実現します。このクロージャは二つの引数を受け取ります: 出力の"types" (stdoutまたはstderr)と、出力 string そのものです:

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

$result = $process->wait();

Concurrent Processes

Laravel は、同時並行的かつ非同期的な process のプールを管理することも風が吹くように簡単にしてくれます。これにより、多数のタスクを同時に簡単に実行できます。スタートするためには、pool method を呼び出してください。これはIlluminate\Process\Poolのインスタンスを受け取るクロージャを引数に取ります。

このクロージャ内では、 pool に属するプロセスを定義することができます。一度 process pool が start method を使って開始されると、running method を通じて実行中のプロセスのcollectionにアクセスすることができます。

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

ご覧の通り、すべての pool のプロセスが実行を終了し、その結果をwait method を通して解決するのを待つことができます。wait method は、 pool 内の各 process の process 結果インスタンスにキーでアクセスできるようにする、アクセス可能な object という array を返します。

$results = $pool->wait();

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

また、便宜上、concurrently method を使用して非同期の process プールを開始し、すぐにその結果を待つことができます。これは、PHP の array デストラクチャリング機能と組み合わせることで特に表現力豊かな構文を提供することができます。

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

Pool プロセスの命名

process プールの結果を数 valueskey でアクセスすることはあまり表現力がありません。したがって、Laravel では、プール内の各 process に stringkey を割り当てることができます。これは、as method を通じて行います。この key はまた、start method に提供されたクロージャにも渡され、どの process のアウトプットに属しているかを判断することができます。

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

Pool Process ID とシグナル

process プールのrunning method で、 pool 内のすべての呼び出されたプロセスの collection が提供されるため、基盤となる pool process の ID に簡単にアクセスできます。

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

そして、便宜上、あなたは signal method を process プールに呼び出して、プール内のすべての process に信号を送ることができます:

$pool->signal(SIGUSR2);

Testing

多くの Laravel services は、簡単で表現豊かな test を書くための機能を提供していますが、Laravel の process service も例外ではありません。Process facade の fake method を使うと、Processes が呼び出されたときに Laravel にスタブ化/ダミーの結果を戻すよう指示することができます。

プロセスの偽装

Laravel の fake プロセスを探索するために、 process を呼び出す route を想像してみましょう:

use Illuminate\Support\Facades\Process;
use Illuminate\Support\Facades\Route;

Route::get('/import', function () {
    Process::run('bash import.sh');

    return 'Import complete!';
});

この route を testing する際、 fake method を引数なしで Process facade に呼び出すことで、 Laravel に対して、 process が呼び出された都度、 fake で成功した process の結果を返すよう指示することができます。さらに、指定した process が run されたことさえもassertできます。

<?php

use Illuminate\Process\PendingProcess;
use Illuminate\Contracts\Process\ProcessResult;
use Illuminate\Support\Facades\Process;

test('process is invoked', function () {
    Process::fake();

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

    // Simple process assertion...
    Process::assertRan('bash import.sh');

    // Or, inspecting the process configuration...
    Process::assertRan(function (PendingProcess $process, ProcessResult $result) {
        return $process->command === 'bash import.sh' &&
               $process->timeout === 60;
    });
});
<?php

namespace Tests\Feature;

use Illuminate\Process\PendingProcess;
use Illuminate\Contracts\Process\ProcessResult;
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');

        // Simple process assertion...
        Process::assertRan('bash import.sh');

        // Or, inspecting the process configuration...
        Process::assertRan(function (PendingProcess $process, ProcessResult $result) {
            return $process->command === 'bash import.sh' &&
                   $process->timeout === 60;
        });
    }
}

議論したように、Process facade 上で fake method を呼び出すと、Laravel は常に成功した process 結果を output なしで返すように指示します。ただし、Process facade の result method を使用して、偽の process の output と終了 code を簡単に指定できます:

Process::fake([
    '*' => Process::result(
        output: 'Test output',
        errorOutput: 'Test error output',
        exitCode: 1,
    ),
]);

特定のプロセスの偽装

以前の例でお気づきの通り、Processの facade では、fake の method に array を渡すことで、 process ごとに異なる fake の結果を指定することができます。

配列の keys は、あなたが fake したい command のパターンを表すべきであり、それらに関連する結果です。*文字はワイルドカード文字として使用することができます。まだ偽装されていない process コマンドは実際に呼び出されます。これらのコマンドのスタブ/ fake 結果を作成するために、Processファサードのresult method を使用することができます。

Process::fake([
    'cat *' => Process::result(
        output: 'Test "cat" output',
    ),
    'ls *' => Process::result(
        output: 'Test "ls" output',
    ),
]);

process をフェイク化する際の code または error output をカスタマイズする必要がない場合、 fake process の結果をシンプルな string として指定する方が便利かもしれません。

Process::fake([
    'cat *' => 'Test "cat" output',
    'ls *' => 'Test "ls" output',
]);

Process シーケンスの偽造

あなたが testing しているコードが同じ command で複数のプロセスを呼び出す場合、各 process の呼び出しに異なるフェイクプロセス結果を割り当てることを望むかもしれません。これはProcessfacade のsequencemethod を使って達成できます:

Process::fake([
    'ls *' => Process::sequence()
                ->push(Process::result('First invocation'))
                ->push(Process::result('Second invocation')),
]);

非同期の Process ライフサイクルの偽装

これまでに、主にrun method を使用して同期的に呼び出されるフェイク processes について議論してきました。しかし、startを介して呼び出される非同期 processes と対話するコードを test しようとしている場合、フェイク processes を記述するためのより洗練されたアプローチが必要かもしれません。

例えば、非同期の process とやり取りをする次の route を想像してみましょう:

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';
});

この process を適切に偽装するためには、runningmethod が何回trueを返すべきかを記述できる必要があります。さらに、返されるべき出力の複数行を sequence で指定したい場合もあります。これを達成するために、Processfacade のdescribemethod を使用できます:

Process::fake([
    'bash import.sh' => Process::describe()
            ->output('First line of standard output')
            ->errorOutput('First line of error output')
            ->output('Second line of standard output')
            ->exitCode(0)
            ->iterations(3),
]);

上記の例を詳しく見てみましょう。outputerrorOutputのメソッドを使用して、 output が sequence として返される複数行を指定することができます。exitCode method は、 fake process の最終的な終了 code を指定するために使われます。最後に、iterations method は、running method がtrueを返す回数を指定するために使用できます。

利用可能なアサーション

以前の議論で示したように、 Laravel は、あなたの feature テストに対して複数の process アサーションを提供します。これらのアサーションについて以下でそれぞれ議論します。

assertRan

与えられた process が呼び出されたことを Assert します:

use Illuminate\Support\Facades\Process;

Process::assertRan('ls -la');

assertRanの method はクロージャも受け付けます。これにより、 process および process の結果のインスタンスを受け取り、プロセスの設定された options を検査することができます。このクロージャがtrueを返すと、アサーションは"path"します。

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

$processIlluminate\Process\PendingProcessのインスタンスであり、assertRanクロージャに渡されます。一方、$resultIlluminate\Contracts\Process\ProcessResultのインスタンスです。

assertDidntRun

与えられた process が呼び出されなかったと Assert する:

use Illuminate\Support\Facades\Process;

Process::assertDidntRun('ls -la');

assertRan method と同様に、assertDidntRun method もクロージャを受け入れ、これにより、 process と process の結果のインスタンスを受け取り、プロセスの設定された options を調査することができます。このクロージャがtrueを返すと、アサーションは"失敗"します。

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

assertRanTimes

指定された回数だけ指定された process が呼び出されたことを Assert します:

use Illuminate\Support\Facades\Process;

Process::assertRanTimes('ls -la', times: 3);

assertRanTimes method はクロージャも受け入れ、これにより process 及び process 結果のインスタンスを受け取ることができます。これにより、プロセスの設定された options を調査できます。このクロージャがtrueを返し、指定された回数の process が呼び出された場合、アサーションは"pass"となります。

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

ストレイプロセスの防止

個々のテストや完全なテストスイート全体で呼び出されたすべてのプロセスが偽装されていることを確認したい場合は、preventStrayProcesses method を呼び出すことができます。この method を呼び出した後、 対応する fake の結果がないプロセスは、実際の process を開始するのではなく、例外を throw します:

use Illuminate\Support\Facades\Process;

Process::preventStrayProcesses();

Process::fake([
    'ls *' => 'Test output...',
]);

// Fake response is returned...
Process::run('ls -la');

// An exception is thrown...
Process::run('bash import.sh');

当社サイトでは、Cookie を使用しています。各規約をご確認の上ご利用ください:
Cookie Policy, Privacy Policy および Terms of Use