PHPackages                             skrz/bunny-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. [Queues &amp; Workers](/categories/queues)
4. /
5. skrz/bunny-bundle

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

skrz/bunny-bundle
=================

Symfony bundle that makes using RabbitMQ easy.

v2.0.3(6y ago)969.8k6[2 issues](https://github.com/skrz/bunny-bundle/issues)[1 PRs](https://github.com/skrz/bunny-bundle/pulls)MITPHPPHP &gt;=5.5.9CI failing

Since May 25Pushed 2y ago5 watchersCompare

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

READMEChangelog (7)Dependencies (6)Versions (20)Used By (0)

Skrz\\Bundle\\BunnyBundle
=========================

[](#skrzbundlebunnybundle)

[![Build Status](https://camo.githubusercontent.com/d0ca6a8fbab8f80b8656d787bf2088c99a9e45b2dde6cfc2710d5b1aaea39604/68747470733a2f2f7472617669732d63692e6f72672f736b727a2f62756e6e792d62756e646c652e7376673f6272616e63683d6d6173746572)](https://travis-ci.org/skrz/bunny-bundle)[![Downloads this Month](https://camo.githubusercontent.com/e57a89bcc734cf8a68817819e08af0dae41b5a9899f82761e32f3d0db886795e/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f646d2f736b727a2f62756e6e792d62756e646c652e737667)](https://packagist.org/packages/skrz/bunny-bundle)[![Latest stable](https://camo.githubusercontent.com/1c8b3b49486f6d83bfe51b8fd038d3674e3b183750a4ad006984ec2001511046/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f736b727a2f62756e6e792d62756e646c652e737667)](https://packagist.org/packages/skrz/bunny-bundle)

> Produce and consumer type-safe messages from RabbitMQ queues

Installation
------------

[](#installation)

Add as [Composer](https://getcomposer.org/) dependency:

```
$ composer require skrz/bunny-bundle
```

Then add `BunnyBundle` to Symfony Kernel:

```
use Skrz\Bundle\BunnyBundle\SkrzBunnyBundle;

class AppKernel
{

    public function registerBundles()
    {
        return [
            ...
            new SkrzBunnyBundle()
            ...
        ];
    }

}
```

Usage
-----

[](#usage)

`BunnyBundle` connects `Skrz\Meta` and `Skrz\Bundle\AutowiringBundle`, so that you can produce and consume type-safe messages to/from RabbitMQ.

`BunnyBundle` creates new 2 new stereotypes (see [`AutowiringBundle`'s description](https://github.com/skrz/autowiring-bundle#usage)):

- `@Consumer` - consumer starts listening for messages on given queue/exchange. Whenever message arrives, `handleMessage`method is called.
- `@Producer` - producers must inherit from `Skrz\Bundle\BunnyBundle\AbstractProducer`. They publish type-safe messages to specified exchanges.

When `BunnyBundle` is added to the Symfony kernel, it registers 3 commands:

- `bunny:setup` - creates exchanges, queues and bindings between them according to configuration.
- `bunny:consumer` - starts given consumer.
- `bunny:producer` - utility command that takes JSON-serialized message, routing key and sends it using given producer. Useful for debugging.

### Setup in `services.yml`

[](#setup-in-servicesyml)

`BunnyBundle` uses `bunny` container extension key.

```
bunny:
  host: %bunny.host%          # default: 127.0.0.1
  port: %bunny.port%          # default: 5672
  vhost: %bunny.vhost%        # default: /
  user: %bunny.user%          # default: guest
  password: %bunny.password%  # default: guest

  # make heartbeat as long as longest message processing time in any consumer might take
  heartbeat: 120 # in seconds = 2 minutes, default: 60 seconds

  exchanges:
    change:
      durable: true  # durable means exchange won't be deleted on broker restart
      type: topic    # topic exchanges route messages by given routing key
                     # see https://www.rabbitmq.com/tutorials/amqp-concepts.html#exchange-topic
                     # other possible types: direct, fanout, headers

    change_done:
      durable: true
      type: topic
      bindings:
        - exchange: change  # RabbitMQ-specific functionality = exchange-to-exchange bindings
          routing_key: "#"

  queues:
    product_categorize:
      durable: true
      bindings:
        - exchange: change
          routing_key: "change.product.#"
```

After you have configured all exchanges, queues and bindings between them, run `bunny:setup`:

```
$ ./console bunny:setup
```

Broker entities should be created as configured.

Note that `bunny:setup` does not try to resolve any conflicting declarations, e.g. one time you declare queue as durable and the seconds time as not durable, you have to resolve these yourself.

### Writing producers

[](#writing-producers)

Our example will be async processing of changes in data. Suppose you have products an categories and want to automatically categorize products according to product title and category title. However, the categorization algorithm is quite expensive, so it has to be done async. We will publish any change in product or category to `change` exchange.

Start with data model:

```
class Product
{

    /** @var int */
    protected $id;

    /** @var string */
    protected $title;

    // ... getters, setters, etc.

}

class Category
{

    /** @var int */
    protected $id;

    /** @var string */
    protected $title;

    // ... getters, setters, etc.

}

class Change
{

    /** @var Product  change in product */
    protected $product;

    /** @var Category  change in category */
    protected $category;

    /** @var string  which hostname the change happened on */
    protected $hostname;

    /** @var int  which user made the change */
    protected $userId;

    // ... getters, setters, etc.

}
```

Producer - `ChangeProducer` - will publish changes to `change` exchange. Producers have `beforeMethod` setting - a method on producer that is called before message is serialized and sent to broker. We will pre-process message and set `$hostname` and `$userId`.

```
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorage;

/**
 * @Producer(
 *     exchange="change",
 *     beforeMethod="preProcessMessage",
 *     meta="ChangeMeta"
 * )
 */
class ChangeProducer extends AbstractProducer
{

	/**
	 * @var TokenStorage
	 *
	 * @Autowired
	 */
	public $tokenStorage;

	public function preProcessMessage(Change $change)
	{
		$change
			->setHostname(gethostname())
			->setUserId($this->tokenStorage->getToken()->getUser()->getId());
	}

}
```

`meta` points to `*Meta` class, that will be used to serialized messages.

You can test producer from command line:

```
$ ./console b:p --help
Usage:
 bunny:producer producer-name message [routing-key]

Arguments:
 producer-name         Name of the producer.
 message               Message JSON string.
 routing-key           Message's routing key.
$ ./console bunny:producer Change '{"product":{"id":121,"title":"Razor blades"}}' change.product.test
```

### Writing consumers

[](#writing-consumers)

When writing a consumer using `BunnyBundle`, think of following: consumers can fail - should messages of a failed consumer be redelivered? If so, you should create queue in `services.yml` and consume from given queue. If not, you should specify `exchange` in `@Consumer` annotation - an anonymous queue will be created on consumer startup.

We want messages to be redelivered, so `product_categorize` queue has been created, consumer will consumer from it.

```
use Bunny\Client;
use Bunny\Message;

/**
 * @Consumer(
 *     queue="product_categorize",
 *     meta="ChangeMeta",
 *     maxMessages=1000,
 *     maxSeconds=3600.0,
 *     prefetchCount=1
 * )
 */
class ProductCategorizeConsumer
{

    public function handleMessage(Change $change, Message $message, Channel $channel)
    {
        // ... expensive product categorization algorithm ...

        $channel->ack($message);
    }

}
```

- `maxMessages` &amp; `maxSeconds` - you should always run your consumer under some supervisor, e.g. [supervisord](http://supervisord.org/). PHP can leak memory, after specified number of messages processed / seconds running, consumer will do clean shutdown (flush all messages, disconnect from RabbitMQ) and exit with code `0` - supervisor should automatically restart it.
- `prefetchCount` - if you have more consumer processes consuming from the same queue in parallel, set `prefetchCount=1`to evenly distribute the work between consumers

Known limitations
-----------------

[](#known-limitations)

- If processing of a messages takes longer then heartbeat timeout, RabbitMQ will disconnect client a consumer will crash. It is more of a limitation of PHP (no threads). Heartbeat has to be set high enough.

License
-------

[](#license)

The MIT license. See `LICENSE` file.

###  Health Score

37

—

LowBetter than 83% of packages

Maintenance16

Infrequent updates — may be unmaintained

Popularity34

Limited adoption so far

Community16

Small or concentrated contributor base

Maturity67

Established project with proven stability

 Bus Factor2

2 contributors hold 50%+ of commits

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 ~130 days

Recently: every ~192 days

Total

14

Last Release

2318d ago

Major Versions

v1.6.0 → v2.0.02019-08-17

PHP version history (2 changes)v1.0.0PHP &gt;=5.4

v1.6.0PHP &gt;=5.5.9

### Community

Maintainers

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

---

Top Contributors

[![jakubkulhan](https://avatars.githubusercontent.com/u/95001?v=4)](https://github.com/jakubkulhan "jakubkulhan (12 commits)")[![mzstic](https://avatars.githubusercontent.com/u/4610204?v=4)](https://github.com/mzstic "mzstic (12 commits)")[![klatys](https://avatars.githubusercontent.com/u/725081?v=4)](https://github.com/klatys "klatys (6 commits)")[![simPod](https://avatars.githubusercontent.com/u/327717?v=4)](https://github.com/simPod "simPod (1 commits)")

---

Tags

messagesymfonybundlequeuerabbitmqmessagingAMQPexchangeSymfony Bundlerabbitqueueingbunnysymfonyfw

###  Code Quality

TestsPHPUnit

### Embed Badge

![Health badge](/badges/skrz-bunny-bundle/health.svg)

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

###  Alternatives

[bunny/bunny

Performant pure-PHP AMQP (RabbitMQ) non-blocking ReactPHP library

7426.5M37](/packages/bunny-bunny)[php-amqplib/rabbitmq-bundle

Integrates php-amqplib with Symfony &amp; RabbitMq. Formerly emag-tech-labs/rabbitmq-bundle, oldsound/rabbitmq-bundle.

1.3k20.1M65](/packages/php-amqplib-rabbitmq-bundle)[kdyby/rabbitmq

Integrates php-amqplib with RabbitMq and Nette Framework

30693.1k4](/packages/kdyby-rabbitmq)[prolic/humus-amqp

PHP-AMQP library with RabbitMQ Extensions

76205.4k5](/packages/prolic-humus-amqp)

PHPackages © 2026

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