windwalker/reactor
Reactor is a Windwalker PHP package for building event-driven applications, offering a lightweight reactive layer to wire up listeners, values, and state changes so components respond to updates without boilerplate or tight coupling.
Scope and architecture fit. windwalker/reactor sits in the Windwalker family of decoupled PHP packages. As the name implies, it targets the Reactor pattern — an event-loop / async-dispatch abstraction rather than a data-layer or utility library. That framing matters for Laravel: Laravel's HTTP lifecycle is synchronous and shared-nothing, so a reactor has no place in the request path. Its only viable home is in long-lived processes — queue workers, daemons, CLI supervisors, websocket servers — where an event loop already exists (Swoole/RoadRunner via Octane, or a standalone ReactPHP loop). Fit is therefore narrow but non-zero: real for teams running async workers, irrelevant for standard CRUD apps.
Integration feasibility. It is a Composer/PSR-4 package with no Laravel service provider, facade, or config publish. Any adoption means writing our own bridge: a container binding, a lifecycle hook to start/stop the loop, and error translation into Laravel's exception handler and logger. That is a day of glue work, not a blocker — but it is code we own forever.
Technical risk. This is the dominant concern and it is severe:
| Signal | Reading |
|---|---|
| 0 stars / 0 dependents | No external validation, no battle-testing, no third-party bug reports |
| Windwalker ecosystem | Largely single-maintainer; effective bus factor of 1 |
| No downstream users | Edge cases (backpressure, cancellation, error propagation) are undiscovered |
| Opportunity score 11.67 | Low strategic upside relative to effort |
Add to that unknown PHP version constraints, an unclear security-disclosure path, and abandonment risk with no fork community to inherit the code. For a TPM, the expected-value calculation is simple: the capability overlaps with primitives we already have (Laravel queues, Illuminate\Bus batches, Octane, ReactPHP directly), so we are taking on maintenance liability for something we could otherwise get from a maintained vendor.
Key questions to close before any commitment.
react/event-loop, react/promise, Laravel Horizon, or Octane does not already cover for us?ext-swoole, ext-uv, none) does it require or support?Verdict: treat as evaluate-only, not adopt until question 1 has a concrete, specific answer that our existing stack cannot satisfy.
Stack fit. Only pursue if we already run an async runtime or have a validated need for one (e.g. hundreds of concurrent outbound HTTP calls per job). In a vanilla Laravel app behind PHP-FPM, this package buys nothing and costs a dependency.
Architecture pattern — build a port, not a dependency. Rather than importing the package into domain code, define our own narrow interface (something like EventDispatcher/LoopRunner) in application space and implement it with an adapter. If the package is abandoned or a better option appears, we swap the adapter and delete one file. This also makes the spike reversible, which is the main thing a TPM needs from an experiment on a 0-star library.
Migration path.
dispatch() / the queue driver.Compatibility checks. Confirm Laravel 10/11 and PHP 8.1+ support in composer.json; watch for conflicts with Octane's loop, Swoole coroutine hooks, and any package that assumes a fresh process per request (static caches, once() helpers, container singletons mutated per-request). Composer constraint drift is the likeliest source of a surprise break.
Sequencing rationale. Compatibility and license verification must precede engineering effort — spending two sprints on glue for a package we cannot legally fork or that does not support our PHP version is the classic sunk-cost trap.
Maintenance becomes an internal line item. With no external contributors, we are the de facto maintainers: reviewing the source ourselves, patching PHP-version breakage, and carrying a fork. Budget roughly 10–15% of one engineer's capacity ongoing. If that is not fundable, the answer is no.
Support model. There is no vendor, no SLA, and no community forum. We must name an internal owner, document a runbook (how the loop starts/stops, how to diagnose a hung worker), and accept that incidents route to us first. Incident tooling — Sentry/OpenTelemetry integration, structured logging — has to be wired manually into the loop.
Scaling characteristics. Async only pays off for I/O-bound work. CPU-bound jobs will perform worse than the standard queue, because a single blocked call stalls the whole loop. Long-lived workers also change the memory profile: leaks that a per-request model masks become fatal over hours, so we need worker recycling (max_jobs-style restarts) and per-worker memory alerting from day one.
Failure modes to instrument for.
file_get_contents, synchronous HTTP).Ramp-up. This is a genuine skill investment, not a library install. Engineers need the reactor mental model — non-blocking discipline, promise composition, cancellation. Expect one to two sprints before a mid-level engineer is productive and compliant with the "never block the loop" rule, and expect code review overhead permanently. Compare that to the near-zero ramp-up of dispatch() and the existing queue worker.
Bottom line for planning. Opportunity is low, risk is high, and the capability is largely substitutable. The rational TPM position is a time-boxed spike behind an adapter interface, with an explicit exit criterion and an assumed default of building or buying elsewhere. Do not let this enter a critical path until it has earned it.
How can I help you explore Laravel packages today?