PHPackages                             vrok/messenger-reply - 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. vrok/messenger-reply

ActiveLibrary

vrok/messenger-reply
====================

Symfony messenger middleware &amp; stamps to reply to messages

1.2.0(5mo ago)1188[1 PRs](https://github.com/j-schumann/messenger-reply/pulls)1MITPHPPHP ^8.3CI passing

Since Jun 18Pushed 2mo ago1 watchersCompare

[ Source](https://github.com/j-schumann/messenger-reply)[ Packagist](https://packagist.org/packages/vrok/messenger-reply)[ Docs](https://vrok.de)[ RSS](/packages/vrok-messenger-reply/feed)WikiDiscussions master Synced 6d ago

READMEChangelog (3)Dependencies (5)Versions (5)Used By (1)

vrok/messenger-reply
====================

[](#vrokmessenger-reply)

This is a library to allow symfony/messenger to reply to messages with a result.
This is meant to be used in a setup with AMQP transport and two symfony instances talking to each other over the same broker: e.g. a web frontend and a microservice, where the frontend sends tasks to the service and requests a reply, for example a generated PDF file.

[![CI Status](https://github.com/j-schumann/messenger-reply/actions/workflows/ci.yaml/badge.svg)](https://github.com/j-schumann/messenger-reply/actions)[![Coverage Status](https://camo.githubusercontent.com/36e3ba6a15d6050d003f2835bc34dcc30dda9452c9f649a329acdc577a3523f3/68747470733a2f2f636f766572616c6c732e696f2f7265706f732f6769746875622f6a2d736368756d616e6e2f6d657373656e6765722d7265706c792f62616467652e7376673f6272616e63683d6d6173746572)](https://coveralls.io/github/j-schumann/messenger-reply?branch=master)

Setup
-----

[](#setup)

Installation on both sides (You need the ReplyToStamp on the request side and the middleware + stamp on the receiving side): `composer require vrok/messenger-reply`

You need request and reply message classes that are equal on both sides, e.g. use a shared composer package:

```
namespace MyNamespace\Message;

class GeneratePdfMessage
{
    /**
     * @var string
     */
    private string $latex;

    public function __construct(string $latex)
    {
        $this->latex = $latex;
    }

    /**
     * @return string
     */
    public function getLatex(): string
    {
        return $this->latex;
    }
}

...

namespace MyNamespace\Message;

class PdfResultMessage
{
    private string $pdfContent;

    public function __construct(string $pdfContent)
    {
        $this->pdfContent = $pdfContent;
    }

    /**
     * @return string
     */
    public function getPdfContent(): string
    {
        return $this->pdfContent;
    }
}
```

### Requesting side

[](#requesting-side)

Add a transport for the shared AMQP broker, routing to the *input* of the receiver (having the same exchange and queue name as the receivers *input* queue).

```
framework:
    messenger:
        transports:
            pdf-requests:
                dsn: '%env(MESSENGER_TRANSPORT_DSN)%'
                options:
                    exchange:
                        name: pdf-service
                        type: direct
                        default_publish_routing_key: input
                    queues:
                        input:
                            binding_keys: [input]
                retry_strategy:
                    max_retries: 3
                    # milliseconds delay
                    delay: 1000
                    # causes the delay to be higher before each retry
                    # e.g. 1 second delay, 2 seconds, 4 seconds
                    multiplier: 2
                    max_delay: 0
```

Add a transport for the shared AMQP broker, for receiving the replies (matching the exchange and queue name of the receivers *output* queue): We need separate transports as `messenger:consume [transportname]` consumes all messages in all queues for that transport.

```
framework:
    messenger:
        transports:
            pdf-results:
                dsn: '%env(MESSENGER_TRANSPORT_DSN)%'
                options:
                    exchange:
                        name: pdf-service
                        type: direct
                        default_publish_routing_key: output
                    queues:
                        input:
                            binding_keys: [output]
                retry_strategy:
                    max_retries: 3
                    # milliseconds delay
                    delay: 1000
                    # causes the delay to be higher before each retry
                    # e.g. 1 second delay, 2 seconds, 4 seconds
                    multiplier: 2
                    max_delay: 0
```

Route your requests to the shared transport/queue:

```
framework:
    messenger:
        routing:
            # e.g.
            'MyNamespace\GeneratePdfMessage': pdf-requests
```

### Replying side

[](#replying-side)

Configure the middleware service:

```
services:
    Vrok\MessengerReply\ReplyMiddleware:
        tags:
            - { name: monolog.logger, channel: messenger }
        calls:
            - [setLogger, ['@logger']]
```

Enable the middleware on your message bus:
(We have to disable the default middleware and explicitly define the order as there is no priority option, just adding our service to the middleware-option would add it before send\_middleware. See [symfony/symfony#28568](https://github.com/symfony/symfony/issues/28568))

```
framework:
    messenger:
        buses:
            messenger.bus.default:
                default_middleware: false
                middleware:
                    - {id: 'add_bus_name_stamp_middleware', arguments: ['messenger.bus.default']}
                    - reject_redelivered_message_middleware
                    - dispatch_after_current_bus
                    - failed_message_processing_middleware
                    - send_message
                    - handle_message
                    - Vrok\MessengerReply\ReplyMiddleware
```

Configure an *input* transport where you send messages from the external applications, which are consumed by your worker(s). And an *output* transport where the replies are sent, optimally with one queue for each application sending requests, so the only consume the replies meant for them. We need separate transports as `messenger:consume [transportname]` consumes all messages in all queues for that transport.

```
framework:
    messenger:
        transports:
            input:
                dsn: '%env(MESSENGER_TRANSPORT_DSN)%'
                options:
                    exchange:
                        name: pdf-service
                        type: direct
                        default_publish_routing_key: input
                    queues:
                        input:
                            binding_keys: [input]
                retry_strategy:
                    max_retries: 3
                    # milliseconds delay
                    delay: 1000
                    # causes the delay to be higher before each retry
                    # e.g. 1 second delay, 2 seconds, 4 seconds
                    multiplier: 2
                    max_delay: 0

            output:
                dsn: '%env(MESSENGER_TRANSPORT_DSN)%'
                options:
                    exchange:
                        name: pdf-service
                        type: direct
                        default_publish_routing_key: output
                    queues:
                        output:
                            binding_keys: [output]
                        output_1:
                            binding_keys: [output_1]
                retry_strategy:
                    max_retries: 3
                    # milliseconds delay
                    delay: 1000
                    # causes the delay to be higher before each retry
                    # e.g. 1 second delay, 2 seconds, 4 seconds
                    multiplier: 2
                    max_delay: 0
```

All replies should be routed to the output transport:

```
framework:
    messenger:
        routing:
            # Route your messages to the transports
            '*': output
```

Usage
-----

[](#usage)

Dispatch the request message with the attached ReplyStamp so the receiver knows where to send the replies:

```
    use MyNamespace\GeneratePdfMessage;
    use Vrok\MessengerReply\ReplyToStamp;

    $e = new Envelope(new GeneratePdfMessage('LaTeX content'));
    $this->bus->dispatch($e
        ->with(new ReplyToStamp('output'))
    );
```

Implement a MessageHandler that handles the requests and returns the reply Message object:

```
use MyNamespace\GeneratePdfMessage
use MyNamespace\PdfResultMessage

class GeneratePdfMessageHandler implements
    MessageHandlerInterface
{
    public function __invoke(GeneratePdfMessage $message): PdfResultMessage
    {
        $LaTeX = $message->getLatex();
        $pdfContent = "$LaTeX";
        $reply = new PdfResultMessage($pdfContent);
        return $reply;
    }
}
```

Consume requests (only on the *input* queue!) on the receiver side:

`./bin/console messenger:consume input`

Consume replies (only on the *output* queue!) on the requesting side:

`./bin/console messenger:consume pdf-results`

If you need to know on the requesting side which task to resume etc. with the received reply, you can implement the `Vrok\MessengerReply\TaskIdentifierMessageInterface`(and use the `Vrok\MessengerReply\TaskIdentifierMessageTrait`) on your request and reply message classes to automatically transfer the *task* and/or *identifier*properties given on the request to the reply. We cannot use stamps for this as stamps are not accessible by MessageHandlers.

###  Health Score

47

—

FairBetter than 94% of packages

Maintenance79

Regular maintenance activity

Popularity12

Limited adoption so far

Community11

Small or concentrated contributor base

Maturity73

Established project with proven stability

 Bus Factor1

Top contributor holds 87.1% 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 ~997 days

Total

3

Last Release

164d ago

PHP version history (2 changes)v1.0.0PHP ^7.4

1.1.0PHP ^8.3

### Community

Maintainers

![](https://www.gravatar.com/avatar/ed9373b6806c33f512ca3b63214dd2a2b2621bcbddffcdb99acc66ae7f0324aa?d=identicon)[j-schumann](/maintainers/j-schumann)

---

Top Contributors

[![j-schumann](https://avatars.githubusercontent.com/u/114239?v=4)](https://github.com/j-schumann "j-schumann (27 commits)")[![renovate[bot]](https://avatars.githubusercontent.com/in/2740?v=4)](https://github.com/renovate[bot] "renovate[bot] (4 commits)")

---

Tags

middlewaresymfonyMessengerreplyreplyTo

###  Code Quality

TestsPHPUnit

Static AnalysisRector

Code StylePHP CS Fixer

### Embed Badge

![Health badge](/badges/vrok-messenger-reply/health.svg)

```
[![Health](https://phpackages.com/badges/vrok-messenger-reply/health.svg)](https://phpackages.com/packages/vrok-messenger-reply)
```

###  Alternatives

[kafkiansky/symfony-middleware

PSR-15 Middleware for symfony.

7959.6k](/packages/kafkiansky-symfony-middleware)

PHPackages © 2026

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