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

Roadrunner Tcp Laravel Package

spiral/roadrunner-tcp

RoadRunner TCP plugin provides PHP workers for RoadRunner's high-performance TCP server, letting you replace classic TCP setups with greater flexibility and speed. Install with Composer and pair with spiral/roadrunner for the app server.

View on GitHub
Deep Wiki
Context7

Getting Started

  1. Install the renamed package at ^4.3.1:

    composer require roadrunner/tcp:^4.3.1
    

    The package was renamed from spiral/roadrunner-tcp to roadrunner/tcp. Update your composer.json requirement and lockfile — the old spiral/roadrunner-tcp name is a different, frozen line. Also confirm the class namespace after the rename (Spiral\RoadRunner\TCP\... vs RoadRunner\TCP\...) by inspecting vendor/roadrunner/tcp/src; the composer name and the PHP namespace do not necessarily move in lockstep, so check before mass-renaming use statements.

  2. Take 4.3.1, not 4.3.0: 4.3.1 fixes the package's Composer requirement, which previously pulled spiral/roadrunner (the v2-era bridge) instead of roadrunner/roadrunner. If you installed 4.3.0, you may have the wrong RoadRunner PHP bridge in your lockfile without any visible error:

    composer update roadrunner/tcp --with-dependencies
    composer show | grep -Ei 'roadrunner'
    

    You want roadrunner/tcp and roadrunner/roadrunner; a leftover spiral/roadrunner entry is a v2 artifact — drop it if nothing else in your tree needs it.

  3. Upgrade to RoadRunner v3: v4.3.0+ adds explicit RoadRunner v3 support and expects a v3 config. The v2 shape in the previous assessment no longer applies — the worker command moved under server, and the config declares a version:

    version: '3'
    
    server:
      command: "php worker.php"
    
    pool:
      num_workers: 4
      max_jobs: 500
      ttl: 0
    
    tcp:
      listen: "tcp://127.0.0.1:6001"
    

    Run rr serve -c .rr.yaml and confirm the TCP listener actually binds before debugging PHP — a silent plugin/config failure looks identical to a worker that never accepts.

  4. First use case: a minimal echo/binary RPC worker. Instantiate the worker once outside the loop and reuse it for the whole process lifetime:

    use Spiral\RoadRunner\TCP\Worker; // verify namespace on v4.3+
    use Relay\Relay;
    
    $worker = new Worker();
    $relay  = new Relay();
    
    while ($relay->accept($worker)) {
        $payload = $worker->read();
        $worker->write('OK');
    }
    

Implementation Patterns

  • Request/response over TCP: read()/write() give you a byte stream, not messages. Define your framing contract up front (length-prefix, newline-delimited, TLV) and put encode/decode in a dedicated class so client and server cannot drift.

  • Binary payloads: For protobuf/msgpack/app structs, use a fixed header + payload or a 4-byte big-endian length prefix (pack('N', strlen($body))). Keep the framing layer separate from the codec so you can swap serializers without touching transport code.

  • Pool-per-purpose: Run dedicated TCP pools for distinct workloads (e.g. tcp-proxy, queue-bridge) and use max_jobs/ttl on the v3 pool config to recycle workers before memory drifts. Prefer max_jobs over a TTL for deterministic recycling.

  • Client-side usage: Use the package client from CLI tools and sibling services:

    $client = new Spiral\RoadRunner\TCP\Client('127.0.0.1:6001');
    $client->write($frame);
    $response = $client->read();
    
  • Laravel integration: Do not boot the framework per message. Bootstrap Laravel once in worker.php, resolve a handler from the container inside the loop, and reset per-request state (auth user, DB transactions, queued listeners) between messages. Expose the worker as an artisan command for local testing (php artisan tcp:serve) that speaks the same framing as production. If you also run a Laravel/RoadRunner bridge that still declares spiral/roadrunner, expect both bridge packages to coexist after 4.3.1 — that's fine, but verify each resolves to a version targeting RR v3.

  • Upgrade pattern: Bump roadrunner/tcp, roadrunner/roadrunner, and the RoadRunner binary together in the same deploy. The v3 protocol/relay changes mean a v4.3 PHP worker against a v2 rr binary fails in confusing ways (handshake or relay errors, not a clear version message).

  • Dependency audit as a step: Add composer show roadrunner/tcp roadrunner/roadrunner to your upgrade checklist/CI output. The 4.3.1 fix was purely a dependency correction, so regressions in this area are invisible in application code and only show up as runtime handshake failures.

Gotchas and Tips

  • 4.3.0 can silently install the wrong bridge: The bug fixed in 4.3.1 is a wrong Composer requirement, not a code bug — so a 4.3.0 install looks perfectly healthy while giving you v2-era RoadRunner classes. If you hit handshake/relay errors on a fresh 4.3.x deploy, check the installed bridge before touching .rr.yaml.

  • Package rename breaks CI caching: composer require spiral/roadrunner-tcp still resolves on old projects, so a stale lockfile or CI image can silently keep you on v4.2. Pin roadrunner/tcp:^4.3.1 and confirm with composer show roadrunner/tcp.

  • RoadRunner v3 is a hard requirement: v4.3.0+ is not a drop-in for v2 deployments. Audit .rr.yaml for the v3 schema (version, server.command, rpc.listen), and check any custom plugins or rr CLI flags in your Dockerfile/Makefile.

  • Framing is still manual: TCP has no message boundaries. A short read or a coalesced read will corrupt your protocol if you assume one read() equals one message. Always loop until your length prefix is satisfied, and test with nc sending partial frames.

  • Long-lived workers leak: Reset the Laravel container's request-scoped bindings each iteration, avoid unbounded static caches, and call gc_collect_cycles() periodically. max_jobs is your safety net, not your strategy.

  • Blocking I/O and timeouts: read()/write() can block for the whole worker slot. Set socket timeouts at connect time or wrap handlers so a single stuck client can't starve the pool.

  • No discovery or load balancing: Transport only. Put HAProxy/nginx-stream in front, or resolve backends from Redis/config in the client.

  • Extension points: Hook the RoadRunner worker lifecycle (v3 event classes) to flush buffers, close DB connections, and commit/rollback before the worker is recycled.

  • Debugging: bin2hex() your frames during development, and keep a plaintext echo handler behind a config flag so you can validate connectivity with nc independently of your binary codec.

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.
steadrun/laravel-monitor
labyrinthe/connect-laravel
elmogy/layan
drewdan/sentinel-client
dskripchenko/laravel-llm
fatryst/nuonuo
stevenay/myanfont
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