Use Cases

This page collects realistic usage patterns that map well to the current public API.

Parallel fan-out of independent tasks

Use one callback and multiple workers when each unit of work can be handled independently.

<?php

declare(strict_types=1);

use FastForward\Fork\Manager\ForkManager;
use FastForward\Fork\Worker\WorkerInterface;

$manager = new ForkManager();

$group = $manager->fork(
    static function (WorkerInterface $worker): int {
        echo sprintf("worker %d processing batch\n", $worker->getPid());
        usleep(200_000);

        return 0;
    },
    4,
);

$group->wait();

Long-running workers with graceful shutdown

Combine a custom or default signal handler with long-running workers that emit heartbeats or consume a queue.

<?php

declare(strict_types=1);

use FastForward\Fork\Manager\ForkManager;
use FastForward\Fork\Signal\DefaultSignalHandler;
use FastForward\Fork\Worker\WorkerInterface;

$manager = new ForkManager(
    signalHandler: new DefaultSignalHandler(exitOnSignal: false),
);

$group = $manager->fork(
    static function (WorkerInterface $worker): int {
        while (true) {
            echo sprintf("worker %d heartbeat\n", $worker->getPid());
            usleep(100_000);
        }
    },
    2,
);

Selective shutdown

If you create more than one group, the manager can target just a subset.

<?php

declare(strict_types=1);

use FastForward\Fork\Manager\ForkManager;
use FastForward\Fork\Signal\Signal;
use FastForward\Fork\Worker\WorkerInterface;

$manager = new ForkManager();

$apiGroup = $manager->fork(
    static fn (WorkerInterface $worker): int => 0,
    2,
);

$queueGroup = $manager->fork(
    static fn (WorkerInterface $worker): int => 0,
    2,
);

$queueWorkers = array_values($queueGroup->all());
$selectedWorker = $queueWorkers[0];

$manager->kill(Signal::Terminate, $apiGroup, $selectedWorker);
$manager->wait($apiGroup, $selectedWorker);

Partial output inspection

You can use worker output as a progress channel while the work is still running.

<?php

declare(strict_types=1);

use FastForward\Fork\Manager\ForkManager;
use FastForward\Fork\Worker\WorkerInterface;

$manager = new ForkManager();

$group = $manager->fork(
    static function (WorkerInterface $worker): int {
        echo sprintf("worker %d started\n", $worker->getPid());
        usleep(500_000);
        echo sprintf("worker %d finished\n", $worker->getPid());

        return 0;
    },
    2,
);

foreach ($group->all() as $worker) {
    echo $worker->getOutput();
}

$group->wait();

Worker-created subprocess trees

If a worker needs its own subprocesses, instantiate a new manager inside that worker. Do not reuse the parent manager instance.

This keeps the process tree explicit and avoids logic errors caused by mixing multiple orchestration roots into one manager instance.