PHPackages                             zwilias/qman - 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. zwilias/qman

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

zwilias/qman
============

An evented beanstalkd queue manager

0.1.4(10y ago)122MITPHPPHP &gt;=5.5.0

Since Jan 5Pushed 10y ago2 watchersCompare

[ Source](https://github.com/zwilias/qman)[ Packagist](https://packagist.org/packages/zwilias/qman)[ RSS](/packages/zwilias-qman/feed)WikiDiscussions master Synced 1mo ago

READMEChangelog (5)Dependencies (6)Versions (8)Used By (0)

QMan
====

[](#qman)

> An evented beanstalkd queue manager.

[![Build Status](https://camo.githubusercontent.com/c128190d146fc8a45bc73d2d42867895f214aa76b42f6a81b2ed0aac8ec2afbd/68747470733a2f2f7472617669732d63692e6f72672f7a77696c6961732f716d616e2e7376673f6272616e63683d6d6173746572)](https://travis-ci.org/zwilias/qman)[![Scrutinizer Code Quality](https://camo.githubusercontent.com/20be85dac7d61d9e52a3b7c08bcd659337238ba6255ed337288647c9a9a5bf55/68747470733a2f2f7363727574696e697a65722d63692e636f6d2f672f7a77696c6961732f716d616e2f6261646765732f7175616c6974792d73636f72652e706e673f623d6d6173746572)](https://scrutinizer-ci.com/g/zwilias/qman/?branch=master)[![Code Coverage](https://camo.githubusercontent.com/ea0c88eb2086c127b400d4cb2f417885f35d93c037fa452eaf905d093a81ebd2/68747470733a2f2f7363727574696e697a65722d63692e636f6d2f672f7a77696c6961732f716d616e2f6261646765732f636f7665726167652e706e673f623d6d6173746572)](https://scrutinizer-ci.com/g/zwilias/qman/?branch=master)[![Latest Stable Version](https://camo.githubusercontent.com/d75abbd21dea45d4bfaf27e568abd40be8cfd3265ff5a305015927d95170398e/68747470733a2f2f706f7365722e707567782e6f72672f7a77696c6961732f716d616e2f762f737461626c65)](https://packagist.org/packages/zwilias/qman)[![Total Downloads](https://camo.githubusercontent.com/c52fda96cb5f3b36f298b65bc9f543296545ece46a4c6fa14030b1dd62b98441/68747470733a2f2f706f7365722e707567782e6f72672f7a77696c6961732f716d616e2f646f776e6c6f616473)](https://packagist.org/packages/zwilias/qman)[![SensioLabsInsight](https://camo.githubusercontent.com/b494df40d735413e2cafcc36e786987d67d9d872580fb7d877912a6e0785f5a4/68747470733a2f2f696e73696768742e73656e73696f6c6162732e636f6d2f70726f6a656374732f38613666663062622d353035392d346363322d393661342d6537316438663931363832362f6d696e692e706e67)](https://insight.sensiolabs.com/projects/8a6ff0bb-5059-4cc2-96a4-e71d8f916826)

Core features
-------------

[](#core-features)

- Sane defaults, highly extensible and configurable
- Allows effortless reserving from a connection pool
- Supports graceful shutdown upon receiving a signal
- Protects job-execution from unexpected intrusions
- Extensible job-failure handling
- Built-in support for fine-grained PSR-3 logging
- Built-in support for queueing closures

Requirements
------------

[](#requirements)

- PHP 5.5, PHP 5.6. [`ev`](https://pecl.php.net/package/ev) does not support PHP 7 yet.
- the pcntl extension.
- [`ev`](https://pecl.php.net/package/ev), an interface to libev, the high performance full-featured event-loop.
- one or more instances of beanstalkd.

Use case
--------

[](#use-case)

QMan is optimized for multiple beanstalkd instances and a pool of workers listening to all of those.

[![HTML View on Gliffy](https://camo.githubusercontent.com/01a6d6fdfe5f605fe5896ca124e5a9c0dad8c35abfc84da79bbddb9ce73df2a2/687474703a2f2f7777772e676c696666792e636f6d2f676f2f7075626c6973682f696d6167652f383633303236312f4c2e706e67)](http://www.gliffy.com/go/publish/8630261)

Examples
--------

[](#examples)

### Queueing a closure

[](#queueing-a-closure)

Queueing a closure is quite possibly the easiest thing

```
use QMan\QMan;

$qMan = QMan::create(['localhost:11300']);
$qMan->queueClosure(function () {
    echo 'Hello world!';
});
```

Essentially, this is equivalent to the following:

```
use QMan\QMan;
use QMan\ClosureCommand;

$qMan = QMan::create(['localhost:11300']);
$qMan->queue(ClosureCommand::create(function () {
    echo 'Hello world!';
}));
```

### Working the queue

[](#working-the-queue)

Starting a worker with all the defaults injected, is easy:

```
use Beanie\Beanie;
use QMan\WorkerBuilder;

$beanie = Beanie::pool(['localhost:11300']);
$worker = (new WorkerBuilder())
    ->build($beanie);

$worker->run();
```

The `WorkerBuilder` ensures the `QMan\Worker` is setup with all of its required dependencies and configuration.

### Queueing custom commands

[](#queueing-custom-commands)

The `ClosureCommand`, while convenient, comes with two major downsides:

- Serializing closures is rather expensive, in terms of computational power required
- Unit-testing closures quickly devolves into a huge mess

As such, you'll quickly be writing custom commands on a regular basis.

A command should implement `QMan\CommandInterface`, which is easily done through extending `QMan\AbstractCommand`:

```
use QMan\AbstractCommand;

class CustomCommand extends AbstractCommand
{
    public function getType()
    {
        return 'my.custom.command';
    }

    public function execute()
    {
        echo $this->getData() * 5;
        return true;
    }
}
```

The `getType()` function should return a string which can be uniquely mapped to the class you want to execute. This indirection is required in order to safely handle picking up stuff like renamed classes through a simple restart of the worker.

In order for the QMan worker to pick up and execute your command, you'll need to make sure the instance of `CommandSerializerInterface` will pick it up. QMan comes with a generic implementation of this interface, aptly named `GenericCommandSerializer`. Let's make sure the class we created above is properly registered:

```
use Beanie\Beanie;
use QMan\WorkerBuilder;
use QMan\GenericCommandSerializer;

$serializer = new GenericCommandSerializer();
$serializer->registerCommandType('my.custom.command', CustomCommand::class);

$beanie = Beanie::pool(['localhost:11300']);
$worker = (new WorkerBuilder())
    ->withCommandSerializer($serializer)
    ->build($beanie);

$worker->run();
```

You could easily futureproof your application by gathering this type &lt;-&gt; class mapping, and representing the types as constants:

```
final class Commands
{
    const TYPE_CUSTOM_COMMAND = 'my.custom.command';

    public static function $map = [
        self::TYPE_CUSTOM_COMMAND => CustomCommand::class
    ];
}
```

QMan's `GenericCommandSerializer` comes with a `registerCommandTypes($map)` function which can handle exactly the case described above.

### Configuration

[](#configuration)

Each `Worker` receives an instance of `QManConfig`. The following properties are currently included:

PropertyDefaultDescription`maxMemoryUsage`20MBAs soon as your memory usage goes over `maxMemoryUsage`, the worker is killed.`maxTimeAlive`24hYour worker will be killed after `maxTimeAlive` passes. Workers are expected to be run in something like supervisord so they can be automatically restarted.`terminationSignals``[SIGTERM]`Upon receiving this signal - while idle - the worker will gracefully shut down. If the signal is sent while a job is being processed, handling the signal will be postponed until the job is fully processed.`maxTries`3 The maximal number of times a job can be executed resulting in failure before the job is buried. (1)`defaultFailureDelay`60sEvery time a job fails, it is released again, with a certain delay. The first time it is released, the delay will be `defaultFailureDelay`. The second time, it will be twice that, etc. (1)*(1)*: Assuming you're using the default `GenericJobFailureStrategy`. Implementing a custom strategy for handling failed jobs is, of course, perfectly possible.

Changing configuration is as simple as instantiating `QManConfig`, setting your configuration preferences and passing it to the `CommandBuilder`:

```
use QMan\QManConfig;
use QMan\QManBuilder;
use Beanie\Beanie;

$config = new QManConfig();
$config->setTerminationSignals([SIGTERM, SIGQUIT]);

$beanie = Beanie::pool($servers);

$worker = (new WorkerBuilder())
    ->withQManConfig($config)
    ->build($beanie);
```

### Handling failed jobs

[](#handling-failed-jobs)

By default, qMan will employ a very simple strategy when handling failed jobs:

- a failed job will either be buried or released again
- if a job has failed less than `maxTries` times in a row, it will be released with `(tries in a row) * defaultFailureDelay`
- else, when it has failed `maxTries` times in a row, it will be buried

Overriding this behavior can be done easily by implementing `JobFailureStrategyInterface` (which extends both PSR-3's `LoggerAwareInterface` and qMan's `ConfigAwareInterface`.

```
use Psr\Log\LoggerAwareTrait;
use QMan\JobFailureStrategyInterface;
use QMan\Job;
use QMan\ConfigAwareTrait;

class MyCustomJobFailureStrategy implements JobFailureStrategyInterface
{
    use LoggerAwareTrait, ConfigAwareTrait;

    public function handleFailedJob(Job $job)
    {
        // Do stuff, like deleting the job after 10 total tries
        $stats = $job->stats();

        if ($stats['reserves'] > 10) {
            $this->logger->alert('Deleting job after failing to successfully execute over 10 times', ['job' => $job]);
            $job->delete();
        }
    }
}

use QMan\WorkerBuilder;

$worker = (new WorkerBuilder)->withJobFailureStrategy(new MyCustomJobFailureStrategy())->build([...]);
```

Contributing
------------

[](#contributing)

Pull requests are appreciated. Make sure code-quality (according to [scrutinizer](https://scrutinizer-ci.com/)) doesn't suffer too badly and all code is thoroughly unit-tested.

Running the tests locally:

```
$ git clone https://github.com/zwilias/qman.git
$ cd qman
$ composer install
$ vendor/bin/phpunit

```

License
-------

[](#license)

Copyright (c) 2015 Ilias Van Peer

Released under the MIT License, see the enclosed `LICENSE` file.

###  Health Score

25

—

LowBetter than 37% of packages

Maintenance20

Infrequent updates — may be unmaintained

Popularity8

Limited adoption so far

Community8

Small or concentrated contributor base

Maturity53

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.

###  Release Activity

Cadence

Every ~4 days

Total

6

Last Release

3759d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/8261843cef72448e4ebfb83b88355888d332b84e7143ed0f3d5eccf77d108fdb?d=identicon)[zwilias](/maintainers/zwilias)

---

Top Contributors

[![zwilias](https://avatars.githubusercontent.com/u/1038427?v=4)](https://github.com/zwilias "zwilias (2 commits)")

---

Tags

queuejobclosurebeanstalkdeventloopworkerbeanstalklibev

###  Code Quality

TestsPHPUnit

### Embed Badge

![Health badge](/badges/zwilias-qman/health.svg)

```
[![Health](https://phpackages.com/badges/zwilias-qman/health.svg)](https://phpackages.com/packages/zwilias-qman)
```

###  Alternatives

[clue/mq-react

Mini Queue, the lightweight in-memory message queue to concurrently do many (but not too many) things at once, built on top of ReactPHP

144691.7k4](/packages/clue-mq-react)[davidpersson/beanstalk

Minimalistic PHP client for beanstalkd.

200321.9k8](/packages/davidpersson-beanstalk)[tarantool/queue

PHP bindings for Tarantool Queue.

64136.2k4](/packages/tarantool-queue)[foxxmd/laravel-elasticbeanstalk-queue-worker

Deploy your Laravel application as a queue worker on AWS ElasticBeanstalk

5493.5k](/packages/foxxmd-laravel-elasticbeanstalk-queue-worker)[xobotyi/beansclient

PHP7.1+ client for beanstalkd work queue with no dependencies

9226.8k](/packages/xobotyi-beansclient)[pmatseykanets/artisan-beans

Easily manage your Beanstalkd job queues right from the Laravel artisan command

4482.1k](/packages/pmatseykanets-artisan-beans)

PHPackages © 2026

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