Skip to content

Commit

Permalink
v6.0.0 release (#9)
Browse files Browse the repository at this point in the history
* add tests and major cleanup/simplification
* gh actions setup
* finalize docs
* update changelog
  • Loading branch information
sweikenb authored Sep 30, 2023
1 parent 0c25885 commit 792d5dd
Show file tree
Hide file tree
Showing 62 changed files with 3,583 additions and 742 deletions.
60 changes: 60 additions & 0 deletions .github/workflows/docs.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
# Sample workflow for building and deploying a mdBook site to GitHub Pages
#
# To get started with mdBook see: https://rust-lang.github.io/mdBook/index.html
#
name: Build Documentation

on:
# Runs on pushes targeting the default branch
push:
branches: ["main", "cleanup-and-tests"]

# Allows you to run this workflow manually from the Actions tab
workflow_dispatch:

# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages
permissions:
contents: read
pages: write
id-token: write

# Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued.
# However, do NOT cancel in-progress runs as we want to allow these production deployments to complete.
concurrency:
group: "pages"
cancel-in-progress: false

jobs:
# Build job
build:
runs-on: ubuntu-latest
env:
MDBOOK_VERSION: 0.4.21
steps:
- uses: actions/checkout@v3
- name: Install mdBook
run: |
curl --proto '=https' --tlsv1.2 https://sh.rustup.rs -sSf -y | sh
rustup update
cargo install --version ${MDBOOK_VERSION} mdbook
- name: Setup Pages
id: pages
uses: actions/configure-pages@v3
- name: Build with mdBook
run: mdbook build docs
- name: Upload artifact
uses: actions/upload-pages-artifact@v2
with:
path: ./docs/book

# Deployment job
deploy:
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
runs-on: ubuntu-latest
needs: build
steps:
- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@v2
43 changes: 43 additions & 0 deletions .github/workflows/phpunit.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
name: PHPUnit Tests

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

permissions:
contents: read

jobs:
phpunit:
name: PHPUnit
runs-on: ubuntu-latest

strategy:
fail-fast: false
matrix:
php-version:
- "8.2"
dependency-versions:
- "lowest"
- "highest"

steps:
- name: Checkout source
uses: actions/checkout@v3

- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: ${{ matrix.php-version }}
extensions: pcntl, posix, sockets
coverage: none

- name: Install composer dependencies
uses: ramsey/composer-install@v2
with:
dependency-versions: ${{ matrix.dependency-versions }}

- name: Run test-suite
run: composer run-script phpunit
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
.idea
vendor
composer.lock
.phpunit.*
docs/book
19 changes: 19 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,24 @@
# Changelog

## Release [v6.0.0](https://github.com/sweikenb/pcntl/releases/tag/v6.0.0)

**Bugfixes**

- Sending IPC messages will now honor the returned bytes of the written buffer correctly

- **Features**

- `ProcessOutput` allows to modify the console output beside the default `STDOUT` and `STDERR`
- Unit and functional tests added using PHPUnit and GitHub actions
- Dedicated documentation added with static rendering using [mdBook](https://rust-lang.github.io/mdBook/) and GitHub
actions

**Breaking Changes**

- `ProcessPool` has been removed in favor of the more simplistic `ProcessQueue` approach

* * *

## Release [v5.0.0](https://github.com/sweikenb/pcntl/releases/tag/v5.0.0)

**Features**
Expand Down
194 changes: 12 additions & 182 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,201 +1,31 @@
# 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 .
![Build status](https://github.com/sweikenb/pcntl/actions/workflows/phpunit.yml/badge.svg)

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

**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](https://sweikenb.github.io/pcntl/)
- [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();
```

## 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.

```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));
});
}
composer require "sweikenb/pcntl"
```

# Basic Example
## Basic Usage

```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"
}
}
6 changes: 6 additions & 0 deletions docs/book.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
[book]
authors = ["Simon Schröer and Contributors"]
language = "en"
multilingual = false
src = "src"
title = "Documentation"
13 changes: 13 additions & 0 deletions docs/src/SUMMARY.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Summary

[Installation](installation.md)

# Features

- [Process Manager](features/process-manager.md)
- [Process Queue](features/process-queue.md)
- [Inter Process Communication (IPC)](features/ipc.md)

# Troubleshoot

- [Common Pitfalls](common-pitfalls-and-workarounds.md)
Loading

0 comments on commit 792d5dd

Please sign in to comment.