peridot-php/peridot-concurrency
Run Peridot specs concurrently with this plugin for the Peridot PHP testing framework. It speeds up test suites by executing specs in parallel, with configurable concurrency and process handling for faster feedback.
Install via Composer and register the plugin in your root peridot.php:
composer require --dev peridot-php/peridot-concurrency
// peridot.php
use Peridot\Concurrency\ConcurrencyPlugin;
return function ($emitter) {
$emitter->usePlugin(new ConcurrencyPlugin());
};
First thing to check after install: run vendor/bin/peridot --help and look for the added concurrency options (typically --concurrency / -c and sometimes --jobs). The exact flag names are the fastest way to confirm the plugin actually attached — if they're absent, the plugin isn't being loaded, or you're using an incompatible Peridot major version.
Your first real use case is a suite that has grown slow (multiple minutes) and where individual specs are independent — no shared fixtures, no order dependence, no shared temp files. Pick a handful of spec files, run peridot -c 4, and diff the wall-clock time against a serial run before rolling it out to CI. Don't start by turning on concurrency for the whole suite; start with the slowest, most isolated directory.
Per-directory enablement. Concurrency is usually a per-run decision, not a per-project one. Keep the plugin registered unconditionally and gate the worker count on an env var so developers run serially by default and CI opts in:
return function ($emitter) {
$emitter->usePlugin(new ConcurrencyPlugin());
// e.g. concurrency: getenv('PERIDOT_CONCURRENCY') ?: 1
};
Isolate by file, not by spec. The runner fans out across spec files/processes. Treat a spec file as the unit of parallelism: put slow integration-style specs in their own files rather than cramming dozens of unrelated fast unit specs into one, otherwise you can't get parallelism where you want it.
Pair with a fast bootstrap. Each worker pays the bootstrap cost (autoloader, container wiring, DB connection). Keep the Peridot bootstrap file lean — defer expensive setup into per-file before hooks so workers only pay for what they use.
CI integration. Run the concurrent suite as a separate CI job from the serial suite, so a flaky parallel run doesn't block on serial failures and vice versa. Emit JUnit XML from Peridot's reporter so your CI can still attribute failures to specific spec files even though output is interleaved.
Compose with a coverage step, not inside it. Concurrent workers can't safely co-write a single coverage file. If you need coverage, either run it serially or use a per-process coverage format and merge afterward — don't try to point all workers at one file.
Output interleaving is real and confusing. With multiple workers writing to stdout, failure output can be scrambled or out of order. When debugging a failure, rerun the specific file serially (peridot path/to/spec.php) — never trust the interleaved transcript for diagnosis.
Shared state breaks silently. Any global written by a spec (static caches, singletons, putenv, shared SQLite//tmp files, a fixture directory keyed by name) will collide across workers. Namespace anything a spec writes: use getmypid() or a unique temp dir per process.
Exit codes and fail-fast. A concurrent runner may not propagate a non-zero exit code reliably when one worker crashes mid-run — verify in CI that a deliberately failing spec actually fails the build. Fail-fast (--stop-on-failure style flags) is usually incompatible with parallelism; don't rely on it here.
Debugging requires falling back. Xdebug, var_dump, and step debuggers are painful across forked processes. Keep a known-good serial invocation (peridot -c 1, or disable the plugin) as your debugging baseline, and make it the default for local dev.
Version pinning matters more than usual. The repo is unmaintained/lightly used (12★), so pin the exact version in composer.json and pin Peridot itself to a compatible range in the same commit. A Peridot minor bump can silently orphan this plugin's event hooks — if concurrency flags vanish after a composer update, that's the cause, not your peridot.php.
Configuration quirks. Worker count above your CPU core count rarely helps and often hurts for I/O-light PHP unit specs. Start at nproc and walk down; the sweet spot is usually 2–4. Also watch that any plugin ordering in peridot.php places the concurrency plugin so its hooks fire around the environment setup, not inside it.
Extension point for custom reporters. If your reporter assumes a single sequential event stream, it will misreport under concurrency. Route reporter output through per-worker files or a serialized channel, and validate your reporter against a -c 4 run before trusting its output in CI.
How can I help you explore Laravel packages today?