webpatser/torque
Torque is a lightweight Laravel package by webpatser that offers a clean, fluent API for common application tasks. It integrates smoothly into existing Laravel projects and is easy to install and configure, making it a practical choice for small projects and rapid prototyping.
Bottom line: v0.8.0 is a credibility release more than a capability release. The headline feature (igbinary) is opt-in and low-risk; the more consequential content is the bug it exposed, the benchmark harness that lets us validate vendor claims on our own hardware, and a README that now tells some users not to adopt. That last point is a positive signal for a pre-1.0 package.
Architecture fit. Torque is a Laravel queue driver built on Redis Streams with consumer groups and Fiber-based concurrency, positioned against the redis driver that Horizon sits on. It fits workloads dominated by async I/O and fan-out — the two profiles where the published numbers are strongest. It does not fit handlers that are DB-bound: the release notes explicitly concede the "Eloquent trap," where blocking PDO calls collapse Fiber concurrency and erase the throughput advantage. That is not a bug, but it is an architectural constraint that has to be designed around (MysqlPool, or pre-fetching at dispatch), and it is the single biggest determinant of whether we see any of the advertised benefit.
Integration feasibility. Low friction at the code level. The serializer is additive config with an env-driven default of json; the StreamQueue constructor parameter change is backwards compatible; ext-igbinary is a composer suggest, not a require. The one operational prerequisite is that torque:bench v1 requires --use-running-master, meaning throughput validation needs a prepared staging master rather than a one-command run on a laptop. Self-spawning and per-stage breakdown (serialize/xadd/xreadgroup/handle/xack) are deferred to v1.1, so the bench today gives us end-to-end throughput and p50/p95/p99 latency but not attribution — if we're slow, it won't tell us where.
Technical risk.
StreamQueue already changed in this release (mitigated by the default). Pin exactly and treat every minor as a review.StreamJob::payload() inherited a JSON-only base implementation, so igbinary workers crashed with a TypeError on a readonly property, jobs piled up, and the bench tail timed out. The note states plainly that the JSON path "was incidentally exercising the only code path that worked." The defect is fixed and isValidPayload now sniffs both formats, but it implies the serializer dimension was untested until the Horizon comparison kit forced it. Assume other config-var-dependent paths (worker count, Fiber concurrency) have similar coverage gaps.async-io fan-out, fanout), and not yet independently reproduced. The reproduction kit materially improves trust, but the kit auto-detects the host Laravel app from cwd, which is fragile in CI and means "reproducible" still depends on environment discipline.Key questions. (1) Does a missing ext-igbinary with TORQUE_SERIALIZER=igbinary set fail fast, or silently fall back to JSON? The install hint suggests fallback; if so, a partial base-image rollout degrades quietly. (2) Who owns Redis Streams operations on our side — Streams, consumer groups and PEL are a different operational model than list-based queues. (3) Is our workload actually fan-out or async-I/O, or is it DB-bound handlers that would need MysqlPool first? (4) What is the support model for a v0.x package — active maintainer, internal fork, or vendor commitment? (5) What is the recovery runbook if the consumer group wedges or PEL grows unbounded? (6) Does live job progress carry a UI dependency we'd have to build?
Stack fit. Requires PHP 8.1+ for Fibers and a Redis version supporting Streams and consumer groups. It is additive to an existing Laravel app: a separate queue connection, no Horizon dependency, and the redis driver can stay in place for everything else. That coexistence is what makes this assessable at all.
Compatibility. No breaking changes for existing installs. The new top-level serializer key defaults via env('TORQUE_SERIALIZER', 'json'), so unpinned configs behave identically. Decode sniffing tolerates a mixed-version worker fleet mid-rollout, which is the property that makes a canary deployment viable. composer.json only suggests the extension — note that a suggest does not guarantee it exists in our base image.
Migration path. Strangle, don't cut over. Keep Horizon on the bulk of queues; route one low-risk, high-fan-out queue to Torque and hold it there through at least one release cycle. Baseline first with torque:bench --use-running-master on hardware comparable to production, so the adoption decision rests on our numbers rather than BENCHMARKS.md. Stay on the JSON serializer for the entire migration — redis-cli XRANGE readability during debugging is worth more than throughput until the queue is boring. Move to igbinary only per-queue, only for payload-large-shaped work, and only once the base image is verified.
Sequencing. (1) Confirm PHP/Redis versions and pin the package at v0.8.0. (2) Stand up staging master, run torque:bench across async-io, fanout and payload-large for a baseline; capture --json output into CI for upgrade diffs. (3) Migrate one queue, JSON serializer, no igbinary. (4) Address the Eloquent trap in handlers before scaling workers — MysqlPool or pre-fetch at dispatch. (5) Enable live job progress once the queue is stable. (6) Evaluate igbinary as a separate, reversible change with a one-line env flip and its own soak.
Maintenance. Pre-1.0 with a meaningful release cadence. Budget recurring review time per minor version — this release alone touched four payload call sites, two validation paths, the connector, the config file and the job class. Plan to re-run torque:bench and diff the JSON output on every upgrade; that is now the cheapest regression signal available.
Support. No LTS, and debugging story diverges by serializer: JSON keeps redis-cli XRANGE usable for on-call, igbinary removes it. If we adopt igbinary, on-call needs a documented decode helper before the first incident, not after. Per-stage breakdown not arriving until v1.1 also means performance escalations will be harder to triage in the interim.
Scaling. The throughput and memory claims are real if handlers are non-blocking. The scaling trap is that adding workers to a Fiber pool saturated by blocking PDO makes things worse, not better. This needs a code-review gate on any handler on a Torque queue. Conversely, the 95%-lower-memory-at-equivalent-throughput figure is the more interesting number for us — it changes instance sizing, not just wall-clock.
Failure modes. The observed one is backlog growth from undecodable payloads; the fix now validates via isValidPayload rather than json_validate, so igbinary blobs are no longer dropped as corrupt. Remaining risks: silent serializer fallback across a heterogeneous fleet, unbounded consumer-group/PEL growth if a worker dies holding messages, and benchmark/CI reproduction breaking because the kit infers the host app from cwd. Alert on queue depth and pending-entries, not just on worker liveness.
Ramp-up. The team needs Redis Streams literacy — XADD, XREADGROUP, XACK, PEL semantics — which is a genuinely different mental model from list-based queues, and a different failure vocabulary. torque:bench shortens this considerably because it makes the concurrency and serializer tradeoffs observable in minutes. The new "When to use Horizon instead" section also reduces misadoption risk, which is worth more to us than any single feature in this release. Estimate: one engineer-week to productive, plus a half-day of team-level knowledge transfer on Streams operations.
How can I help you explore Laravel packages today?