PHPackages                             andreybolonin/ratchet-bundle - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. andreybolonin/ratchet-bundle

ActiveLibrary

andreybolonin/ratchet-bundle
============================

Ratchet Symfony bundle

11PHP

Since Jun 4Pushed 7y ago1 watchersCompare

[ Source](https://github.com/andreybolonin/RatchetBundle)[ Packagist](https://packagist.org/packages/andreybolonin/ratchet-bundle)[ RSS](/packages/andreybolonin-ratchet-bundle/feed)WikiDiscussions master Synced today

READMEChangelogDependenciesVersions (1)Used By (0)

QuickStart
==========

[](#quickstart)

### 0) Check, do you install high perfomance C event extension (libevent, libev, libuv)

[](#0-check-do-you-install-high-perfomance-c-event-extension-libevent-libev-libuv)

Connectionsstream\_selectlibevent10010.6569.29850011.1759.79180017.3279.709100023.2829.749

`libevent` vs `libev`

`libev` vs `libuv`

### 1) Set ulimit

[](#1-set-ulimit)

add to `/etc/security/limits.conf`

```
*               soft    nofile          1000000
*               hard    nofile          1000000
```

add to `/etc/sysctl.conf`

`fs.file-max=1000000`

relogin to your server and check

`ulimit -n` should be `1000000`

### 2) Install

[](#2-install)

`composer req andreybolonin/ratchet-bundle`

### 3) Define your pool

[](#3-define-your-pool)

`config/packages/ratchet_bundle.yaml`

```
ratchet_bundle:
    wampserver_pool: ['127.0.0.1:8095', '127.0.0.1:8097', '127.0.0.1:8099']
```

### 4) Run your nodes

[](#4-run-your-nodes)

`bin/console wamp:server:run --host=127.0.0.1 --port=8095`

`bin/console wamp:server:run --host=127.0.0.1 --port=8097`

`bin/console wamp:server:run --host=127.0.0.1 --port=8099`

### 5) Setup NGINX (as load balancer)

[](#5-setup-nginx-as-load-balancer)

`/etc/nginx/nginx.conf`

```
worker_processes        auto;
worker_rlimit_nofile    49152;
timer_resolution        100ms;
worker_priority         -5;

events {
    use epoll;
    worker_connections 24576;
    multi_accept on;
}
```

`/etc/nginx/sites-enabled/*`

```
upstream socket {
    server 127.0.0.1:8095;
    server 127.0.0.1:8097;
    server 127.0.0.1:8099;
}

map $http_upgrade $connection_upgrade {
    default upgrade;
    ''      close;
}

server {
	server_name 127.0.0.1;
	listen 8090;

	proxy_next_upstream error;
	proxy_set_header X-Real-IP $remote_addr;
	proxy_set_header X-Scheme $scheme;
	proxy_set_header Host $http_host;

	location / {
		proxy_pass http://socket;
                proxy_http_version 1.1;
                proxy_set_header Upgrade $http_upgrade;
                proxy_set_header Connection "upgrade";
                proxy_set_header Host $host;

                proxy_set_header X-Real-IP $remote_addr;
                proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
                proxy_set_header X-Forwarded-Proto https;
                proxy_read_timeout 86400; # neccessary to avoid websocket timeout disconnect
                proxy_redirect off;
	}
}
```

[http://nginx.org/en/docs/http/load\_balancing.html](http://nginx.org/en/docs/http/load_balancing.html)

### 6) Define your Topic-class:

[](#6-define-your-topic-class)

```
em = $em;
        $this->counter = $counter;
        $this->router = $router;

        $this->wampserver_broadcast = $wampserver_broadcast;
        $this->websocket_this_node = $websocket_this_node;

        $key = array_search($this->websocket_this_node, $this->wampserver_broadcast);
        unset($this->wampserver_broadcast[$key]);
    }

    /**
     * This will receive any Subscription requests for this topic.
     *
     * @param ConnectionInterface $connection
     * @param Topic               $topic
     */
    public function onSubscribe(ConnectionInterface $connection, $topic)
    {
        //this will broadcast the message to ALL subscribers of this topic.
        $topic->broadcast(['msg' => $connection->resourceId.' has joined '.$topic->getId()]);
    }

    /**
     * This will receive any UnSubscription requests for this topic.
     *
     * @param ConnectionInterface $connection
     * @param Topic               $topic
     */
    public function onUnSubscribe(ConnectionInterface $connection, $topic)
    {
        //this will broadcast the message to ALL subscribers of this topic.
        $topic->broadcast(['msg' => $connection->resourceId.' has left '.$topic->getId()]);
    }

    /**
     * Онлайн-торги.
     *
     * This will receive any Publish requests for this topic.
     *
     * @param ConnectionInterface $connection
     * @param Topic               $topic
     * @param $event
     * @param array $exclude
     * @param array $eligible
     *
     * @return mixed|void
     */
    public function onPublish(ConnectionInterface $connection, $topic, $event, array $exclude, array $eligible)
    {
        switch ($topic->getId()) {
            case 'counter/channel':
                $this->CounterTopic($connection, $topic, $event, $exclude, $eligible);
                break;

            case 'price/channel':
                $this->PriceTopic($connection, $topic, $event, $exclude, $eligible);
                break;

            case 'broadcast/channel':
                $this->BroadcastTopic($connection, $topic, $event, $exclude, $eligible);
                break;
        }
    }

    /**
     * Counter Topic.
     *
     * This will receive any Publish requests for this topic.
     *
     * @param ConnectionInterface $connection
     * @param Topic               $topic
     * @param $event
     * @param array $exclude
     * @param array $eligible
     *
     * @return mixed|void
     */
    public function CounterTopic(ConnectionInterface $connection, $topic, $event, array $exclude, array $eligible)
    {
	// если все лоты сняты или проданы - снимаем сессию
	if ($allLotsSales) {
	    $session->setDateFinished(new \DateTime());
	    $event['finishUrl'] = $this->router->generate('cabinet_session_finish', ['session_id' => $session->getId()]);
	    $topic->broadcast($event);
	    $this->broadcast($event);
	} else {
	    $connection->event($topic->getId(), $event);
	}
    }

    /**
     * Price Topic.
     *
     * This will receive any Publish requests for this topic.
     *я
     *
     * @param ConnectionInterface $connection
     * @param Topic               $topic
     * @param $event
     * @param array $exclude
     * @param array $eligible
     *
     * @return mixed|void
     */
    public function PriceTopic(ConnectionInterface $connection, $topic, $event, array $exclude, array $eligible)
    {
        if ($lots && $buyer && Lot::STATUS_ON_BIDDING == $lots[0]->getStatus()) {
                $topic->broadcast($event);
                $this->broadcast($event);
            } else {
                $connection->event($topic->getId(), false);
            }
        } else {
            $connection->event($topic->getId(), false);
        }
    }

    /**
     * BroadcastTopic.
     *
     * This will receive any Publish requests for this topic.
     *
     * @param ConnectionInterface $connection
     * @param Topic               $topic
     * @param $event
     * @param array $exclude
     * @param array $eligible
     *
     * @return mixed|void
     */
    public function BroadcastTopic(ConnectionInterface $connection, $topic, $event, array $exclude, array $eligible)
    {
        $topic->broadcast($event);
    }

    public function onCall(ConnectionInterface $connection, $id, $topic, array $params)
    {
        $connection->callError($id, $topic, 'RPC not supported on this demo');
    }

    public function onOpen(ConnectionInterface $connection)
    {
        echo $connection->resourceId.' connected'.PHP_EOL;
    }

    public function onClose(ConnectionInterface $connection)
    {
        echo $connection->resourceId.' disconnected'.PHP_EOL;
    }

    public function onError(ConnectionInterface $connection, \Exception $e)
    {
        echo 'connection error occurred: '.$e->getMessage().PHP_EOL;
    }

    /**
     * @param array $event
     *
     * @throws \Gos\Component\WebSocketClient\Exception\BadResponseException
     * @throws \Gos\Component\WebSocketClient\Exception\WebsocketException
     */
    public function broadcast(array $event)
    {
        foreach ($this->wampserver_broadcast as $broadcast) {
            $host = parse_url($broadcast, PHP_URL_HOST);
            $port = parse_url($broadcast, PHP_URL_PORT);
            var_dump($host.':'.$port);
            $client = new Client($host, $port);
            $client->connect();
            $client->publish('broadcast/channel', $event);
            $client->disconnect();
        }
    }
}
```

```
    app.bidding_topic_service:
        class: App\Topic\BiddingTopic
        arguments:
            $em: '@doctrine.orm.entity_manager'
            $counter: '@app.service.counter'
            $router: '@Symfony\Component\Routing\RouterInterface'
        public: true
        lazy: true
```

### 7) Inject

[](#7-inject)

`use RatchetMultiInstanceTrait;` into your Topic-class

### 8) Send the

[](#8-send-the)

`$topic->broadcast($event)` with `$this->broadcast($event)` for broadcasting in another WampServer nodes

### 9) Benchmark

[](#9-benchmark)

`wrk -t4 -c400 -d10s ws://127.0.0.1:8090`

1 node (828req/sec)

2 node (4.410req/sec)

[![](https://raw.githubusercontent.com/andreybolonin/RatchetBundle/master/bench.png)](https://raw.githubusercontent.com/andreybolonin/RatchetBundle/master/bench.png)

### 10) Arch

[](#10-arch)

Is something differnt of [https://nodejs.org/api/cluster.html#cluster\_cluster](https://nodejs.org/api/cluster.html#cluster_cluster)

[![](https://raw.githubusercontent.com/andreybolonin/RatchetMultiInstance/master/RatchetMultiInstance.png)](https://raw.githubusercontent.com/andreybolonin/RatchetMultiInstance/master/RatchetMultiInstance.png)

###  Health Score

19

—

LowBetter than 10% of packages

Maintenance20

Infrequent updates — may be unmaintained

Popularity3

Limited adoption so far

Community7

Small or concentrated contributor base

Maturity40

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

### Community

Maintainers

![](https://www.gravatar.com/avatar/adc3d0e11e285a41f126df479eeb9c7b00107008c507b177ea2921ae1c314eda?d=identicon)[andreybolonin](/maintainers/andreybolonin)

---

Top Contributors

[![andreybolonin](https://avatars.githubusercontent.com/u/2576509?v=4)](https://github.com/andreybolonin "andreybolonin (22 commits)")

### Embed Badge

![Health badge](/badges/andreybolonin-ratchet-bundle/health.svg)

```
[![Health](https://phpackages.com/badges/andreybolonin-ratchet-bundle/health.svg)](https://phpackages.com/packages/andreybolonin-ratchet-bundle)
```

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
