PHPackages                             sbooker/event-loop-worker - 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. [Queues &amp; Workers](/categories/queues)
4. /
5. sbooker/event-loop-worker

ActiveLibrary[Queues &amp; Workers](/categories/queues)

sbooker/event-loop-worker
=========================

ReactPHP's event loop based worker

1.2.1(2y ago)04.7k1MITPHPPHP ^7.4 | ^8.0CI failing

Since Jun 3Pushed 10mo ago1 watchersCompare

[ Source](https://github.com/sbooker/event-loop-worker)[ Packagist](https://packagist.org/packages/sbooker/event-loop-worker)[ RSS](/packages/sbooker-event-loop-worker/feed)WikiDiscussions master Synced 3w ago

READMEChangelog (2)Dependencies (4)Versions (8)Used By (0)

[Read in English](README.EN.md)

Event Loop Worker (`sbooker/event-loop-worker`)
===============================================

[](#event-loop-worker-sbookerevent-loop-worker)

[![Latest Version](https://camo.githubusercontent.com/2c314a115af8c36245ca86473b893a93fec873bd3397927d2a17d8621e5601d6/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f73626f6f6b65722f6576656e742d6c6f6f702d776f726b65722e7376673f7374796c653d666c61742d737175617265)](https://img.shields.io/packagist/v/sbooker/event-loop-worker)[![Software License](https://camo.githubusercontent.com/55c0218c8f8009f06ad4ddae837ddd05301481fcf0dff8e0ed9dadda8780713e/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6c6963656e73652d4d49542d627269676874677265656e2e7376673f7374796c653d666c61742d737175617265)](https://github.com/sbooker/event-loop-worker/blob/master/LICENSE)[![PHP Version](https://camo.githubusercontent.com/a19ea7afa3fd767ebf56f6df16b735b24008b70adae9dc1562871fc897bcd697/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f7068702d762f73626f6f6b65722f6576656e742d6c6f6f702d776f726b65722e7376673f7374796c653d666c61742d737175617265)](https://php.net)[![Total Downloads](https://camo.githubusercontent.com/7575a5923120ebc738eb3bf952814e9dfa366baa24cf4a11293f36c56c278386/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f64742f73626f6f6b65722f6576656e742d6c6f6f702d776f726b65722e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/sbooker/event-loop-worker)

Асинхронный, production-ready воркер на базе [ReactPHP EventLoop](https://reactphp.org/event-loop/).

Назначение библиотеки
---------------------

[](#назначение-библиотеки)

### Проблема: наивные воркеры

[](#проблема-наивные-воркеры)

Для фоновой обработки задач часто используются два подхода, и оба имеют серьезные недостатки:

**1. "Вечный" `while`-цикл с `sleep()`:**

```
while (true) {
    if (!$handler->handleNext()) {
        sleep(5);
    }
}
```

- **Недостатки:** Неэффективный поллинг, блокирующие операции, фиксированная задержка.

**2. Команда, запускаемая по `cron`:**

```
// Запускается каждую минуту по cron
while ($handler->handleNext()) { /* ... */ }
```

- **Недостатки:**
    - **Высокая задержка:** Новая задача будет ждать до минуты, прежде чем ее обработка начнется.
    - **Пиковые нагрузки:** Создает пиковую нагрузку на ресурсы в начале каждой минуты.
    - **Проблемы с параллельным запуском:** Если обработка занимает больше минуты, следующий `cron`-процесс может запуститься параллельно.

Попытки "починить" `cron` с помощью **мьютексов (механизмов блокировки)** для предотвращения параллельного запуска лишь создают новые проблемы:

- **Блокировка на файлах:** Плохо работает в многосерверной или контейнеризированной среде.
- **Блокировка в Redis:** Требует развертывания и поддержки дополнительной инфраструктуры.
- **Блокировка в БД:** Создает дополнительную нагрузку на базу данных и может приводить к дедлокам.

### Решение: умный воркер на Event Loop

[](#решение-умный-воркер-на-event-loop)

Эта библиотека решает все эти проблемы, предоставляя **постоянно работающий (демонизированный) воркер** на базе event loop. Он запускается один раз и работает непрерывно.

**Главная особенность** — стратегия `Doubled` (экспоненциальная задержка). Воркер:

1. Часто проверяет наличие новых задач, когда они есть (например, каждые 0.1с).
2. Если задач нет, он **экспоненциально увеличивает** интервал ожидания (например, 1с, 2с, 4с, 8с...) до заданного максимума.
3. Как только новая задача появляется и обрабатывается, интервал снова сбрасывается до минимального.

Это позволяет создать **высокоотзывчивый и одновременно очень экономичный** воркер.

Ключевые особенности
--------------------

[](#ключевые-особенности)

- **Асинхронная основа:** Построен на `react/event-loop`, что обеспечивает неблокирующую работу.
- **Умные стратегии ожидания:** Включает `Periodic` (постоянный интервал) и `Doubled` (экспоненциальная задержка) для экономии ресурсов.
- **Корректное завершение работы:** Перехватывает сигналы `SIGINT` и `SIGTERM` для graceful shutdown.
- **Компонуемость:** Позволяет запускать **несколько разных обработчиков** (например, основной и ping для поддержания открытого соединения с БД) в рамках одного воркера.
- **Простая интеграция:** Любой ваш обработчик может быть адаптирован через простой интерфейс `Workable`.

Установка
---------

[](#установка)

```
composer require sbooker/event-loop-worker
```

**Зависимости:**

- `react/event-loop`

Быстрый старт
-------------

[](#быстрый-старт)

### Шаг 1: Адаптируйте ваш обработчик

[](#шаг-1-адаптируйте-ваш-обработчик)

Вам нужен класс, реализующий интерфейс `Workable`. Библиотека `sbooker/command-bus` уже предоставляет готовый адаптер `CommandProcessor`.

```
// bootstrap.php
use Sbooker\CommandBus\Handler;
use Sbooker\CommandBus\Infrastructure\Worker\CommandProcessor;

/** @var Handler $commandHandler */ // Ваш обработчик из command-bus

// Просто оборачиваем его в Workable-адаптер
$workable = new CommandProcessor($commandHandler);
```

### Шаг 2: Создайте консольную команду воркера

[](#шаг-2-создайте-консольную-команду-воркера)

Создайте класс, унаследованный от `Symfony\Component\Console\Command`, и используйте `WorkerFactory` для его конфигурации.

```
// src/Command/RunWorkerCommand.php
use Sbooker\EventLoopWorker\WorkerFactory;
use Sbooker\EventLoopWorker\Workable;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;

final class RunWorkerCommand extends Command
{
    private WorkerFactory $workerFactory;
    private Workable $workable; // Ваш адаптированный обработчик

    // ... constructor ...

    protected function execute(InputInterface $input, OutputInterface $output): int
    {
        // Создаем воркер с экспоненциальной задержкой.
        // Это наиболее рекомендуемый вариант.
        $worker = $this->workerFactory->createDoubled(
            $this->workable,
            0.1,   // Минимальный таймаут (когда есть работа)
            300.0, // Максимальный таймаут (когда работы долго нет)
            1.0    // Начальный таймаут
        );

        // Запускаем вечный цикл
        return $worker->run($input, $output);
    }
}
```

### Шаг 3: Запустите воркер

[](#шаг-3-запустите-воркер)

Теперь вы можете запустить ваш воркер из консоли.

```
php bin/console app:run-worker
```

Продвинутое использование
-------------------------

[](#продвинутое-использование)

### Решение проблемы "Connection timed out" с PostgreSQL

[](#решение-проблемы-connection-timed-out-с-postgresql)

Долгоживущие процессы, работающие с PostgreSQL, часто сталкиваются с проблемой разрыва соединения, если в течение некоторого времени нет запросов.

Метод `createDoubledWithPeriodic` идеально решает эту проблему. Вы можете использовать его, чтобы наряду с основной задачей запускать очень легкую периодическую задачу (например, `SELECT 1`), которая будет поддерживать соединение "живым".

**1. Создайте "пингующий" `Workable`:**

```
// src/Infrastructure/Persistence/ConnectionPinger.php
use Doctrine\DBAL\Connection;
use Sbooker\EventLoopWorker\Workable;

final class ConnectionPinger implements Workable
{
    private Connection $connection;
    public function __construct(Connection $connection) { $this->connection = $connection; }

    public function process(): bool
    {
        $this->connection->executeQuery('SELECT 1');
        return true; // Всегда возвращаем true, т.к. "работа" была выполнена
    }
}
```

**2. Используйте его в воркере:**

```
// src/Command/RunWorkerCommand.php

/** @var Workable $commandProcessor */
/** @var ConnectionPinger $pinger */

$worker =
    $this->workerFactory->createDoubledWithPeriodic(
        $commandProcessor, // Основная задача
        $pinger,           // Задача для "пинга" соединения
        0.1,
        300.0,
        1.0,
        30.0 // "Пинговать" соединение каждые 30 секунд
    );

return $worker->run($input, $output);
```

License
-------

[](#license)

See [LICENSE](https://github.com/sbooker/event-loop-worker/blob/master/LICENSE) file.

###  Health Score

36

—

LowBetter than 79% of packages

Maintenance39

Infrequent updates — may be unmaintained

Popularity18

Limited adoption so far

Community8

Small or concentrated contributor base

Maturity66

Established project with proven stability

 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.

###  Release Activity

Cadence

Every ~368 days

Total

5

Last Release

739d ago

PHP version history (2 changes)1.0.0PHP ^7.4

1.1.0PHP ^7.4 | ^8.0

### Community

Maintainers

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

---

Top Contributors

[![sbooker](https://avatars.githubusercontent.com/u/3658174?v=4)](https://github.com/sbooker "sbooker (6 commits)")

---

Tags

event-loopworkerbackground process

###  Code Quality

TestsPHPUnit

### Embed Badge

![Health badge](/badges/sbooker-event-loop-worker/health.svg)

```
[![Health](https://phpackages.com/badges/sbooker-event-loop-worker/health.svg)](https://phpackages.com/packages/sbooker-event-loop-worker)
```

###  Alternatives

[symfony/messenger

Helps applications send and receive messages to/from other applications or via message queues

1.1k128.6M1.4k](/packages/symfony-messenger)[matomo/matomo

Matomo is the leading Free/Libre open analytics platform

21.6k38.2k](/packages/matomo-matomo)[react/promise-timer

A trivial implementation of timeouts for Promises, built on top of ReactPHP.

34145.7M108](/packages/react-promise-timer)[swarrot/swarrot

A simple lib to consume RabbitMQ queues

3664.4M8](/packages/swarrot-swarrot)[symfony/amazon-sqs-messenger

Symfony Amazon SQS extension Messenger Bridge

4613.5M20](/packages/symfony-amazon-sqs-messenger)

PHPackages © 2026

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