Skip to content

Commit

Permalink
add tests and major cleanup/simplification
Browse files Browse the repository at this point in the history
  • Loading branch information
sweikenb committed Sep 29, 2023
1 parent 0c25885 commit 9130408
Show file tree
Hide file tree
Showing 30 changed files with 581 additions and 743 deletions.
36 changes: 36 additions & 0 deletions .github/workflows/phpunit.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
name: PHP Composer

on:
push:
branches: [ "**" ]
pull_request:
branches: [ "main" ]

permissions:
contents: read

jobs:
build:

runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v3

- name: Validate composer.json and composer.lock
run: composer validate --strict

- name: Cache Composer packages
id: composer-cache
uses: actions/cache@v3
with:
path: vendor
key: ${{ runner.os }}-php-${{ hashFiles('**/composer.lock') }}
restore-keys: |
${{ runner.os }}-php-
- name: Install dependencies
run: composer install --prefer-dist --no-progress

- name: Run test suite
run: composer run-script phpunit
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
.idea
vendor
composer.lock
.phpunit.*
194 changes: 11 additions & 183 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,201 +1,29 @@
# PCNTL Library

Simple and easy to use process manager for PHP based on default PCNTL and POSIX functions.
Simple and easy to use thread-based process manager for PHP based on default PCNTL and POSIX functions.

Please also have a look into the [CHANGELOG](CHANGELOG.md) for latest updates and release information .
**Further information:**

**License**: [MIT](LICENSE.txt)

**Topics**

- [Installation](#installation)
- [Basic Usage](#usage)
- [IPC Inter Process Communication](#inter-process-communication)
- [Pool Processing](#process-pool--worker-processes)
- [Queued Processing](#process-queue)
- [Examples](#basic-example)

* * *
- [Docs](docs/index.md)
- [Changelog](CHANGELOG.md)
- [MIT License](LICENSE.txt)

## Installation

You can install this library by [composer](https://getcomposer.org/):

```bash
composer require sweikenb/pcntl
```

## Usage

You can just create an instance of `\Sweikenb\Library\Pcntl\ProcessManager` and create a process-fork by
calling `runProcess()`.

The manager will handle the rest and makes sure all process will be terminated properly. It will also make sure that
the major system signals will be propagated to the child processes as well. In case you want to define your own set of
signals you want to propagate to the children, you can add an array with the signals as second argument to the
constructor.

**Process flow**

You can _(but you do not have to)_ use the `wait()` method to wait for previously created children. The method can be
called multiple times and allows a very flexible process-flow handling.

Also, to make sure the children are terminated, the process-manager will install a shutdown-function which will call
the `wait()` method automatically at the end of the script. If you do not want this functionality, just pass `false` as
first argument to the constructor to disable the shutdown handler. If you disable this feature, the process manager will
force a child termination even if they aren't finished yet and exits with status-code `125`.

## Inter Process Communication

You can send data between the parent and child process using messages.

The data gets send by sockets and can be anything that can be encoded using `serialize()`:

```php
<?php

use Sweikenb\Library\Pcntl\Api\ChildProcessInterface;
use Sweikenb\Library\Pcntl\Api\ParentProcessInterface;
use Sweikenb\Library\Pcntl\ProcessManager;
use Sweikenb\Library\Pcntl\Model\Ipc\MessageModel;

require "./vendor/autoload.php";

$pm = new ProcessManager();

$child = $pm->runProcess(function(ChildProcessInterface $childProcess, ParentProcessInterface $parentProcess){
$message = $parentProcess->getNextMessage(true);
if ($message) {
// Process message here ...
fwrite(
STDOUT,
fprintf('Got a message from the parent process: %s - %s', $message->getTopic(), $message->getPayload())
);
}
$parentProcess->sendMessage(new MessageModel('some_response', 'hello parent'));
});

$child->sendMessage(new MessageModel('some_topic', 'hello child'));

// wait and cleanup
sleep(3);
$child->kill();
composer require "sweikenb/pcntl"
```

## Process Pool & Worker Processes

You can also distribute workload across multiple worker to work in parallel. The actual work must be placed inside a
class that is invokable _(`__invoke`)_ and must not have a constructor.
## Basic Usage

```php
<?php

use ExampleWorkerService;
use Sweikenb\Library\Pcntl\Factory\WorkerMessageFactory;
use Sweikenb\Library\Pcntl\ProcessPool;

require "./vendor/autoload.php";
$messageFactory = new WorkerMessageFactory();

$numberOfWorkers = 4;
$pool = new ProcessPool($numberOfWorkers);

for($i = 0; $i < 100; $i++) {
$pool->sendMessage($messageFactory->create('some_topic', ExampleWorkerService::class));
}

// wait and cleanup
sleep(5);
$pool->closePool();
```

## Process Queue

In case you want to work with dynamic callbacks instead of a process-pool, which will require predefined worker, you can
use the `ProcessQueue`. This queue limits the number of threads that will be forked and handles the return-management
for you.

```php
<?php

use Sweikenb\Library\Pcntl\Api\ChildProcessInterface;
use Sweikenb\Library\Pcntl\Api\ParentProcessInterface;
use Sweikenb\Library\Pcntl\ProcessQueue;

require __DIR__ . '/../vendor/autoload.php';

$maxNumberOfThreadsToRunParallel = 4;

$queue = new ProcessQueue($maxNumberOfThreadsToRunParallel);

for ($i = 1; $i <= 50; $i++) {
$queue->addToQueue(function (ChildProcessInterface $child, ParentProcessInterface $parent) use ($i) {
sleep(mt_rand(1, 3));
fwrite(STDOUT, sprintf("Queued thread %d processed message no. %d\n", $child->getId(), $i));
});
}
```

# Basic Example

```php
<?php

use Sweikenb\Library\Pcntl\ProcessManager;
use Sweikenb\Library\Pcntl\Api\ChildProcessInterface;
use Sweikenb\Library\Pcntl\Api\ParentProcessInterface;
use Sweikenb\Library\Pcntl\ProcessManager;

require "./vendor/autoload.php";
use Sweikenb\Library\Pcntl\Api\ProcessOutputInterface;

$pm = new ProcessManager();

$pm->runProcess(function(ChildProcessInterface $childProcess, ParentProcessInterface $parentProcess){
sleep(2);
echo "B\n";
$pm->runProcess(function(ChildProcessInterface $child, ParentProcessInterface $parent, ProcessOutputInterface $output) {
$output->stdout(sprintf('Hello World from PID: %d', $child->getId()));
});

$pm->runProcess(function(ChildProcessInterface $childProcess, ParentProcessInterface $parentProcess){
sleep(1);
echo "C\n";
});

$pm->runProcess(function(ChildProcessInterface $childProcess, ParentProcessInterface $parentProcess){
sleep(3);
echo "A\n";
});

$pm->wait(function(ChildProcessInterface $childProcess, ParentProcessInterface $parentProcess){
echo "-> A to C processes finished!\n";
});

$pm->runProcess(function(ChildProcessInterface $childProcess, ParentProcessInterface $parentProcess){
echo "E\n";
});

$pm->runProcess(function(ChildProcessInterface $childProcess, ParentProcessInterface $parentProcess){
sleep(1);
echo "D\n";
});

$pm->wait(function(){
echo "-> D and E processes finished!\n";
});

echo "\n--> All Work done!\n";
```

This script will return the following output:

```bash
C
B
A
-> A to C processes finished!
E
D
-> D and E processes finished!

--> All Work done!
```

More examples can be found in the [example](./example) folder.
11 changes: 11 additions & 0 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,5 +22,16 @@
"psr-4": {
"Sweikenb\\Library\\Pcntl\\": "src"
}
},
"autoload-dev": {
"psr-4": {
"Tests\\": "tests"
}
},
"require-dev": {
"phpunit/phpunit": "^10.3"
},
"scripts": {
"phpunit": "vendor/bin/phpunit --bootstrap vendor/autoload.php --display-warnings tests"
}
}
3 changes: 3 additions & 0 deletions docs/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Documentation

TODO
52 changes: 0 additions & 52 deletions example/000_simple.php

This file was deleted.

Loading

0 comments on commit 9130408

Please sign in to comment.