Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Process Laravel Package

amphp/process

amphp/process is an asynchronous process dispatcher for PHP 8.1+ built on the Revolt event loop. It runs child processes on all major platforms, including Windows, with non-blocking access to stdout and stderr, plus support for custom working directories and environment variables.

View on GitHub
Deep Wiki
Context7

Technical Evaluation

Architecture fit. amphp/process is not a drop-in replacement for Laravel's process layer; it is a primitive for a different execution model. Laravel's default runtime is synchronous and process-per-request, while this package assumes a live Revolt event loop and fiber-based concurrency. It therefore fits cleanly in only a few places:

  • Long-running Artisan daemons / bespoke worker processes that own the event loop end to end.
  • CLI tooling and internal ops scripts where you control the entrypoint (Amp\async, Revolt\EventLoop::run()).
  • An Octane worker only if Revolt can coexist with RoadRunner/Swoole's own loop on your pinned versions — this is unproven and must be spiked, not assumed.

Inside a standard FPM request or a default queue:work job, you'd be booting a mini-runtime inside a synchronous worker. That works, but it inverts the failure mode: any blocking call in that fiber (Eloquent/PDO, file_get_contents, sleep, a synchronous HTTP client) stalls all concurrent children in that process. Verdict: strong fit for a purpose-built async execution tier; poor fit as the app-wide process runner.

Integration feasibility. The API surface is small and stable: static Process::start($command, workingDirectory:, environment:), getStdin/getStdout/getStderr, join(?Cancellation), kill(), signal(), getPid(), getWorkingDirectory(), getEnvironment(), escapeArgument(). v2 replaced promise-returning APIs with direct returns, which reads much closer to synchronous code and lowers the porting cost. Concurrency is delegated to Amp\ByteStream\pipe() and Amp\async(). Realistic integration is a thin adapter — one interface, two implementations (Symfony Process for sync paths, Amp for async paths) — so call sites don't fork and most engineers never touch Amp.

Technical risk.

  • Runtime coupling. Pulls revolt/event-loop and amphp/byte-stream v2. Version alignment with anything else in the tree that uses Amp (Octane, WebSocket servers, PHPUnit plugins) is the most likely Composer-level blocker, and it surfaces as "we can't upgrade Laravel" six months later.
  • Two execution models. The durable cost is cognitive and test-related, not build-related: the codebase now has sync and async paths with different rules, and reviews must gate against blocking calls in the async tier.
  • Windows parity depends on a bundled wrapper executable that gets copied out at runtime, including from PHARs. That has historically been the fragile area (multiple 1.x patch releases) and interacts badly with EDR/AV, read-only container filesystems, and noexec temp mounts.
  • Zombie/orphan handling on *nix depends on optional ext-pcntl; without it you inherit the documented zombie risk. Independently, a SIGKILLed PHP worker leaves children running regardless of library.
  • Signals are platform-divergent; getSignalName() is ext-pcntl-only and returns null otherwise, so signal-based control flow must degrade gracefully.
  • Vendor health. 260 stars and a reported 0 dependents understate real usage — this is usually a transitive dependency of Amp-based stacks — but the visible bus factor is a small core team, MIT, and no documentation beyond README plus changelogs. Acceptable for a thin, well-scoped primitive; not a place to build differentiated logic.

Key questions.

  1. Which workloads are genuinely I/O-bound subprocess work (ffmpeg, headless Chrome/PDF, git, linters, log tailing) versus CPU-bound PHP that gains nothing?
  2. Where will the event loop live — a dedicated deployment unit, or inside Octane? If Octane, has RoadRunner/Swoole + Revolt coexistence been verified on our versions?
  3. What is our timeout/kill contract? join() takes a Cancellation; do we standardize on it, and what happens to grandchildren spawned through shell wrappers on cancellation?
  4. Are we committing to draining stdout and stderr concurrently on every call? (Otherwise: pipe-buffer deadlock.)
  5. Is Windows a real target? If not, declaring the async tier *nix-only removes most of the wrapper and packaging risk.
  6. Does anything in the tree pin amphp/byte-stream v1 or an older Revolt?
  7. Do we need child output in memory, streamed to logs/object storage, or both? That drives backpressure and memory design.

Integration Approach

Stack fit. Position this as infrastructure for a dedicated async execution tier, not as the application's process runner. Illuminate\Process / Symfony Process remains the default everywhere. The package sits behind a domain interface — something like ProcessRunner with runSync() and runAsync() — which keeps the blast radius to one directory and makes the choice reversible per workload.

Migration path.

  1. Introduce the interface plus a Symfony-backed implementation and route existing ad-hoc exec()/shell_exec()/proc_open()/Process::run() call sites through it. Zero behavior change; this alone usually surfaces duplicated, inconsistent subprocess code.
  2. Add an Amp-backed implementation satisfying the same interface, usable only in code paths that own a Revolt loop.
  3. Move a single workload across behind a config flag, measure wall-clock and memory against the serial baseline, then decide whether to expand.

Compatibility. Pin amphp/process ^2 (PHP 8.1+), amphp/byte-stream ^2, revolt/event-loop ^1. Do not attempt to mix v1 and v2 — the promise-to-direct-return change is structural, not cosmetic. Require ext-pcntl in *nix worker images. Make the Windows decision explicit: either support it and account for the wrapper binary in image builds and PHAR packaging, or keep Windows on the sync path permanently and document it.

Sequencing.

  • Phase 0: inventory subprocess call sites; quantify whether serial-plus-more-workers is actually more expensive than async fan-out. This is the go/no-go gate.
  • Phase 1: adapter interface, sync implementation, and one standard helper that drains both pipes, enforces a cancellation timeout, escalates to kill(), and logs exit code + duration + bytes.
  • Phase 2: async tier prototype on the highest-volume, lowest-blast-radius job.
  • Phase 3: observability — duration, exit code, output volume, kill/orphan events — into existing Laravel logging and metrics; alert on nonzero-exit rate and orphan count.
  • Phase 4: broaden adoption, or roll back if the concurrency win doesn't materialize against the operational overhead.

Operational Impact

Maintenance. Small surface area — one primary class plus a few functions — MIT, semver, changelog-only release notes. Realistic annual cost is dependency bumps plus periodic re-verification of the Windows wrapper path. The library isn't the ongoing cost; owning two execution models in one codebase is. Enforce the boundary with a lint rule or review checklist ("no blocking calls in async paths") or it will erode.

Support. No commercial backing, no SLA, community issue tracker. Fine for a thin primitive; the risk is that a bug you hit becomes one you fix upstream or work around. Confirm in advance that forking or vendoring a patched copy is acceptable to whoever owns risk.

Scaling. This is the actual prize: async dispatch decouples "concurrent child processes" from "PHP worker count," letting a handful of PHP processes hold many in-flight ffmpeg/Chrome/git jobs instead of provisioning one Horizon worker per concurrent child. The ceiling is usually the child processes' own CPU/RAM, not PHP. Practical limits to model: file descriptors (3+ per child, more on Windows — watch ulimit -n), fiber and buffer memory, and total container memory. Counterweight: scaling PHP workers is already well understood on our platform; a bespoke async tier brings its own supervision, health checks, and deploy story, which is new operational surface.

Failure modes to design for.

  • Pipe-buffer deadlock if stdout/stderr aren't drained concurrently — mandate it in the shared helper.
  • Blocking inside a fiber stalls every concurrent child in that process, silently converting a fan-out into a serial hang. This is the signature failure of this architecture.
  • No built-in timeout on join(); without a Cancellation policy and kill escalation, hung children hang forever.
  • Orphans and zombies on worker crash or hard kill, especially grandchildren behind shell wrappers. Prefer direct exec over shell strings, track PIDs, add a reaper job, require ext-pcntl.
  • Unbounded output streamed to memory is a memory-exhaustion vector; cap or spool to disk/object storage.
  • Platform drift: the Windows wrapper can trip EDR or fail on read-only/noexec temp dirs; PHAR packaging is the historically fragile path.
  • Composer conflicts during Laravel or Octane upgrades, discovered late as an "unupgradable" dependency.

Ramp-up. The API is an hour of reading; the event-loop/fiber model is the ramp. Expect a half-day onboarding doc plus one complete worked example (a real transcoding or headless-browser job with drain, timeout, kill, and metrics) to make it safe. Keep the adapter interface deliberately boring so the majority of engineers never write Amp code directly and a small owning group maintains the async tier. Before committing to a roadmap, run an explicit spike on the Octane/Revolt coexistence question — and be candid in specs that this buys concurrency for I/O-bound subprocess work only, and does nothing for CPU-bound PHP.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
gmostafa/php-graphql-client
xeviant/paystack
snowsoft/faker
meditationsteps/blogetc
animalyoung/laravel-influxdb
onix-solutions/sms-telera
lonely-lights/prosetta
oxygen/data
oxygen/core
jengo/base
xiloryx/log-collector
a21ns1g4ts/filament-stripe
la-php/laravel-admin
artisan-build/community-prompts
vleroy/smart
ayles-software/laravel-australian-public-holidays
cboxdk/laravel-id-spatie
cboxdk/laravel-id-billing
cboxdk/laravel-id-billing-bridge
simple-as-fuck/php-performance-log