lucinda/process

Light weight API performing single/multiple shell command execution using IO multiplexing

v2.0.3 2022-06-05 07:34 UTC

This package is auto-updated.

Last update: 2024-05-05 11:48:06 UTC


README

This API is a light weight wrapper over PHP proc_* functions, able to execute shell processes individually, pool them or handle streams that traverse them. Its design goals were:

  • platform agnosticity: API doesn't take any assumptions on the operating system process runs into
  • least assumption principle: API doesn't take any assumption how you will handle process streams, so provides a skeleton instead
  • elegance and simplicity: API is written on less is more principle so it's easy to understand and flexible to extend

API is 100% unit tested, fully PSR-4 compliant and only requiring PHP 8.1+ interpreter. For installation, you just need to write this in console:

composer require lucinda/process

Then use one of main classes provided (using use Lucinda\Shell namespace):

  • Stream: encapsulates an abstract data stream to be used by process (eg: STDIN/STDOUT/STDER). Extended by:
    • Stream\Pipe: encapsulates a stream of un-named pipes to be processed immediately
    • Stream\File: encapsulates a stream of that delegates to a file on disk
    • Stream\Resource: encapsulates a stream of that delegates to a resource (eg: socket)
  • Process: encapsulates a single process using Stream instances above
  • Pool: encapsulates a pool of processes to be executed in paralel queue-ing Process instances above and using Process\Multiplexer implementation for processing

Each of above classes branches through its methods to deeper classes that become relevant depending on the complexity of process execution logic. To make things simple following drivers were provided (using Lucinda\Shell\Driver namespace):

Both classes make use of I/O multiplexing that uses SELECT command underneath.

Executing Single Processes

To execute a single shell command you can use Lucinda\Shell\Process for minute control or Lucinda\Shell\Driver\SingleCommandRunner driver provided:

use Lucinda\Shell\Driver\SingleCommandRunner;
use Lucinda\Shell\Process;

$object = new SingleCommandRunner(5);
$result = $object->run(new Process("YOUR_SHELL_COMMAND"));

This is superior to shell_exec because it will:

  • terminate if shell command execution exceeds 5 seconds
  • process STDOUT/STDERR streams separately using IO multiplexing
  • read streams in parallel using chunks
  • automatically escape shell command

Executing Multiple Processes

To execute multiple shell commands at once you can implement your own Lucinda\Shell\Process\Multiplexer for minute control or Lucinda\Shell\Driver\MultiCommandRunner driver provided:

use Lucinda\Shell\Driver\MultiCommandRunner;
use Lucinda\Shell\Process;

$object = new MultiCommandRunner(5);
$results = $object->run([
  new Process("YOUR_SHELL_COMMAND1"),
  new Process("YOUR_SHELL_COMMAND2"),
  ...
]);

This will:

  • open processes simultaneously
  • terminate if ANY of processes exceeds 5 seconds
  • use non-blocking approach, allowing streams processing to be done in parallel
  • automatically escape shell commands

Pooling Multiplexed Processes

To run multiplexed processes in pools of fixed size (5 in this example):

use Lucinda\Shell\Driver\MultiCommandRunner;
use Lucinda\Shell\Process;
use Lucinda\Shell\Pool;

# defines a pool of max 5 capacity
$pool = new Pool(5);
# adds processes to pool
$pool->submit(new Process("YOUR_SHELL_COMMAND1"));
$pool->submit(new Process("YOUR_SHELL_COMMAND2"));
...
# executes processes in batches, delegating to Multiplexer instances
$results = $pool->shutdown(new MultiCommandRunner(5));

This will:

  • execute N processes at same time (5 in above example)
  • when they all end, proceed to next batch