PHPackages                             phpgears/cqrs-async - 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. phpgears/cqrs-async

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

phpgears/cqrs-async
===================

Async CQRS

0.3.1(6y ago)01281MITPHPPHP ^7.1CI failing

Since Sep 29Pushed 5y ago1 watchersCompare

[ Source](https://github.com/phpgears/cqrs-async)[ Packagist](https://packagist.org/packages/phpgears/cqrs-async)[ Docs](https://github.com/phpgears/cqrs-async)[ RSS](/packages/phpgears-cqrs-async/feed)WikiDiscussions master Synced 2w ago

READMEChangelog (1)Dependencies (15)Versions (9)Used By (1)

[![PHP version](https://camo.githubusercontent.com/d0b5687c6812c5d52d86a548e09db527eeb7860f82adbb677de00a36ddbed1b4/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f5048502d253345253344372e312d3838393242462e7376673f7374796c653d666c61742d737175617265)](http://php.net)[![Latest Version](https://camo.githubusercontent.com/baefcfdb05338027a64a9346a7abca196c0f566e070a099ecd4d216be98f39d6/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f70687067656172732f637172732d6173796e632e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/phpgears/cqrs-async)[![License](https://camo.githubusercontent.com/8441b42622132d85ff0372e543fb8687be308cb8e4b97d5c81da539fcf1a1fed/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f6c6963656e73652f70687067656172732f637172732d6173796e632e7376673f7374796c653d666c61742d737175617265)](https://github.com/phpgears/cqrs-async/blob/master/LICENSE)

[![Build Status](https://camo.githubusercontent.com/593bfb18a62531f10fb6581a414735bc7a1ab9c2cfe08954309a46b534117226/68747470733a2f2f696d672e736869656c64732e696f2f7472617669732f636f6d2f70687067656172732f637172732d6173796e632e7376673f7374796c653d666c61742d737175617265)](https://travis-ci.com/github/phpgears/cqrs-async)[![Style Check](https://camo.githubusercontent.com/2f21411a62a5e57cb8a0eb1f09e009886a8441b0e173b1b4e595cb8f1b274593/68747470733a2f2f7374796c6563692e696f2f7265706f732f3135303439373430332f736869656c64)](https://styleci.io/repos/150497403)[![Code Quality](https://camo.githubusercontent.com/fbb498468c0d44bb50b9806e03c12333bac0d129633484ca14bd0910d114e775/68747470733a2f2f696d672e736869656c64732e696f2f7363727574696e697a65722f672f70687067656172732f637172732d6173796e632e7376673f7374796c653d666c61742d737175617265)](https://scrutinizer-ci.com/g/phpgears/cqrs-async)[![Code Coverage](https://camo.githubusercontent.com/291a446581a112b95212709d7410fbc0d3ad0ef83eccdd8a0ba6e7c9d3d47275/68747470733a2f2f696d672e736869656c64732e696f2f636f766572616c6c732f70687067656172732f637172732d6173796e632e7376673f7374796c653d666c61742d737175617265)](https://coveralls.io/github/phpgears/cqrs-async)

[![Total Downloads](https://camo.githubusercontent.com/6a338f1d075b3d10ce534f0cc8b1108552bddedbd942b76c586b945a7055c153/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f64742f70687067656172732f637172732d6173796e632e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/phpgears/cqrs-async/stats)[![Monthly Downloads](https://camo.githubusercontent.com/f4782792e2d1f73352aea046924a9403c1469b1262e312db8f4e0255b84f39c0/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f646d2f70687067656172732f637172732d6173796e632e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/phpgears/cqrs-async/stats)

Async CQRS
==========

[](#async-cqrs)

Async decorator for CQRS command bus

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

[](#installation)

### Composer

[](#composer)

```
composer require phpgears/cqrs-async

```

Usage
-----

[](#usage)

Require composer autoload file

```
require './vendor/autoload.php';
```

### Asynchronous Commands Bus

[](#asynchronous-commands-bus)

Command bus decorator to handle commands asynchronously

#### Enqueue

[](#enqueue)

```
use Gears\CQRS\Async\AsyncCommandBus;
use Gears\CQRS\Async\Serializer\JsonCommandSerializer;
use Gears\CQRS\Async\Discriminator\ParameterCommandDiscriminator;

/* @var \Gears\CQRS\CommandBus $commandBus */

/* @var Gears\CQRS\Async\CommandQueue $commandQueue */
$commandQueue = new CustomCommandQueue(new JsonCommandSerializer());

$asyncCommandBus new AsyncCommandBus(
    $commandBus,
    $commandQueue,
    new ParameterCommandDiscriminator('async')
);

$asyncCommand = new CustomCommand(['async' => true]);

$asyncCommandBus->handle($asyncCommand);
```

#### Dequeue

[](#dequeue)

This part is highly dependent on your message queue, though command serializers can be used to deserialize queue message

This is just an example of the process

```
use Gears\CQRS\Async\ReceivedCommand;
use Gears\CQRS\Async\Serializer\JsonCommandSerializer;

/* @var \Gears\CQRS\Async\AsyncCommandBus $asyncCommandBus */
/* @var your_message_queue_manager $queue */

$serializer = new JsonCommandSerializer();

while (true) {
  $message = $queue->getMessage();

  if ($message !== null) {
    $command = new ReceivedCommand($serializer->fromSerialized($message));

    $asyncCommandBus->handle($command);
  }
}
```

Deserialized commands should be wrapped in Gears\\CQRS\\Async\\ReceivedCommand in order to avoid infinite loops should you decide to handle the commands to an async command bus. If you decide to use a non-async bus on the dequeue side you don't need to do this

### Discriminator

[](#discriminator)

Discriminates whether a command should or should not be enqueued based on arbitrary conditions

Three discriminators are provided in this package

- `Gears\CQRS\Async\Discriminator\ArrayCommandDiscriminator` selects commands if they are present in the array provided
- `Gears\CQRS\Async\Discriminator\ClassCommandDiscriminator` selects commands by their class or interface
- `Gears\CQRS\Async\Discriminator\ParameterCommandDiscriminator` selects commands by the presence of a command payload parameter (optionally by its value as well)

### Command queue

[](#command-queue)

This is the one responsible for actual async handling, which would normally be sending the serialized command to a message queue system such as RabbitMQ

No implementation is provided but an abstract base class so you can extend from it

```
use Gears\CQRS\Async\AbstractCommandQueue;

class CustomCommandQueue extends AbstractCommandQueue
{
  public function send(Command $command): void
  {
    // Do the actual enqueue of $this->getSerializedCommand($command);
  }
}

```

You can use [cqrs-async-queue-interop](https://github.com/phpgears/cqrs-async-queue-interop) that uses [queue-interop](https://github.com/queue-interop/queue-interop) for enqueuing messages

### Serializer

[](#serializer)

Abstract command queue uses serializers to do command serialization so it can be sent to the message queue as a string message

`Gears\CQRS\Async\Serializer\JsonCommandSerializer` is directly provided as a general serializer allowing maximum compatibility in case of commands being handled by other systems

You can create your own serializer if the one provided does not fit your needs, for example by using *JMS serializer*, by implementing `Gears\CQRS\Async\Serializer\CommandSerializer` interface

### Distributed systems

[](#distributed-systems)

On distributed systems, such as micro-service systems, commands can be dequeued on a completely different part of the system, this part should of course know about commands and their contents but could eventually not have access to the command class itself

For example in the context of Domain Events on DDD a bounded context could handle command delivered by another completely different bounded context and of course won't be able to deserialize the original command as it is located on another domain

This can be solved in one of two ways, transform messages coming out from the message queue before handing them to the command serializer, or better by creating a custom `Gears\CQRS\Async\Serializer\CommandSerializer` encapsulating this transformation

*Transformation can be as simple as changing command class to be reconstituted*

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

[](#contributing)

Found a bug or have a feature request? [Please open a new issue](https://github.com/phpgears/cqrs-async/issues). Have a look at existing issues before.

See file [CONTRIBUTING.md](https://github.com/phpgears/cqrs-async/blob/master/CONTRIBUTING.md)

License
-------

[](#license)

See file [LICENSE](https://github.com/phpgears/cqrs-async/blob/master/LICENSE) included with the source code for a copy of the license terms.

###  Health Score

25

—

LowBetter than 36% of packages

Maintenance20

Infrequent updates — may be unmaintained

Popularity10

Limited adoption so far

Community9

Small or concentrated contributor base

Maturity52

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

Recently: every ~82 days

Total

7

Last Release

2460d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/4c50421f1ab4148354dc2dd5dcaba168656b17ea913b310d112deb39a6f73ca1?d=identicon)[juliangut](/maintainers/juliangut)

---

Top Contributors

[![juliangut](https://avatars.githubusercontent.com/u/1104131?v=4)](https://github.com/juliangut "juliangut (13 commits)")

---

Tags

asyncasynchronousquerycommandimmutablecqrs

###  Code Quality

TestsPHPUnit

Static AnalysisPHPStan

Code StylePHP CS Fixer

Type Coverage Yes

### Embed Badge

![Health badge](/badges/phpgears-cqrs-async/health.svg)

```
[![Health](https://phpackages.com/badges/phpgears-cqrs-async/health.svg)](https://phpackages.com/packages/phpgears-cqrs-async)
```

###  Alternatives

[amphp/amp

A non-blocking concurrency framework for PHP applications.

4.4k130.2M407](/packages/amphp-amp)[revolt/event-loop

Rock-solid event loop for concurrent PHP applications.

92550.1M206](/packages/revolt-event-loop)[amphp/parallel

Parallel processing component for Amp.

85249.9M91](/packages/amphp-parallel)[amphp/sync

Non-blocking synchronization primitives for PHP based on Amp and Revolt.

19158.1M51](/packages/amphp-sync)[amphp/serialization

Serialization tools for IPC and data storage in PHP.

13656.4M20](/packages/amphp-serialization)[icicleio/icicle

Icicle is a PHP library for writing asynchronous code using synchronous coding techniques.

1.1k152.2k15](/packages/icicleio-icicle)

PHPackages © 2026

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