Skip to content

Commit 2133b5d

Browse files
committed
REPLACE received stamp with a new message stamp
Deprecates the AzureReceivedStamp and replaces it with a new AzureMessageStamp.
1 parent 5237ffe commit 2133b5d

8 files changed

Lines changed: 372 additions & 133 deletions

File tree

CHANGELOG.md

Lines changed: 23 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,23 @@
1-
# Changelog
2-
All notable changes to this project will be documented in this file.
3-
4-
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
5-
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6-
7-
## [Unreleased]
8-
9-
## [1.0.0] - 2022-02-10
10-
### Added
11-
- **Symfony Messenger** transport for **Azure Service Bus** *queues* and *topics*
12-
13-
[Unreleased]: https://github.com/AymDev/MessengerAzureBundle/compare/v1.0.0...HEAD
14-
[1.0.0]: https://github.com/AymDev/MessengerAzureBundle/releases/tag/v1.0.0
15-
1+
# Changelog
2+
All notable changes to this project will be documented in this file.
3+
4+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
5+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6+
7+
## [Unreleased]
8+
9+
## [1.1.0] - 2022-02-14
10+
### Added
11+
- **AzureMessageStamp** stamp for sent/received messages with *queue*/*topic* name, message, subscription name and delete location
12+
13+
### Deprecated
14+
- **AzureReceivedStamp** in favor of the new **AzureMessageStamp**
15+
16+
## [1.0.0] - 2022-02-10
17+
### Added
18+
- **Symfony Messenger** transport for **Azure Service Bus** *queues* and *topics*
19+
20+
[Unreleased]: https://github.com/AymDev/MessengerAzureBundle/compare/v1.1.0...HEAD
21+
[1.1.0]: https://github.com/AymDev/MessengerAzureBundle/releases/tag/v1.1.0
22+
[1.0.0]: https://github.com/AymDev/MessengerAzureBundle/releases/tag/v1.0.0
23+

README.md

Lines changed: 88 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -1,78 +1,89 @@
1-
# Messenger Azure Service Bus Bundle
2-
A **Symfony 4 / 5 / 6** bundle providing a **Symfony Messenger** *transport* for **Azure Service Bus** using the *Azure REST API*.
3-
4-
![Testing](https://github.com/AymDev/MessengerAzureBundle/workflows/Testing/badge.svg)
5-
![Coding Standards](https://github.com/AymDev/MessengerAzureBundle/workflows/Coding%20Standards/badge.svg)
6-
![Bundle installation](https://github.com/AymDev/MessengerAzureBundle/workflows/Bundle%20installation/badge.svg)
7-
[![Latest Stable Version](https://poser.pugx.org/aymdev/messenger-azure-bundle/v)](//packagist.org/packages/aymdev/messenger-azure-bundle)
8-
[![License](https://poser.pugx.org/aymdev/messenger-azure-bundle/license)](//packagist.org/packages/aymdev/messenger-azure-bundle)
9-
10-
## Installation
11-
12-
You only need to install the bundle using **Composer**:
13-
```shell
14-
composer require aymdev/messenger-azure-bundle
15-
```
16-
As it uses [Symfony HttpClient](https://symfony.com/doc/current/http_client.html),
17-
you will need to install a [PSR-18 client](https://symfony.com/doc/current/http_client.html#psr-18-and-psr-17).
18-
Example:
19-
```shell
20-
composer require nyholm/psr7
21-
```
22-
23-
## Configuration
24-
25-
### Transport DSN
26-
27-
Your DSN must respect the following format to build the authentication header for a specific *namespace*:
28-
```
29-
azure://KEY_NAME:KEY_VALUE@NAMESPACE
30-
```
31-
>Where `KEY_NAME` is your **shared access key name**, `KEY_VALUE` is your **shared access key** and `NAMESPACE` is your
32-
>*Azure Service Bus* **namespace**.
33-
34-
### Transport options
35-
36-
Detailed list of transport options:
37-
38-
| Option name | Description | Required | Default value |
39-
| ------------- | ------------- | ----: | ----: |
40-
| `entity_path` | The **topic** or **queue** name. | Yes | |
41-
| `subscription` | The subcription name to consume messages from a **topic**. | Only for *topic consumer transports* | |
42-
| `token_expiry` | [SAS token](https://docs.microsoft.com/en-us/azure/service-bus-messaging/service-bus-sas#generate-a-shared-access-signature-token) validity duration in seconds. | | `3600` |
43-
| `receive_mode` | Set to `peek-lock` to perform a [non destructive read](https://docs.microsoft.com/en-us/rest/api/servicebus/peek-lock-message-non-destructive-read) or to `receive-and-delete` to perform a [destructive-read](https://docs.microsoft.com/en-us/rest/api/servicebus/receive-and-delete-message-destructive-read) | | `peek-lock` |
44-
45-
Example `config/packages/messenger.yaml`:
46-
```yaml
47-
framework:
48-
messenger:
49-
transports:
50-
azure_transport:
51-
dsn: '%env(AZURE_SERVICE_BUS_DSN)%'
52-
serializer: 'App\Messenger\YourAzureSerializer'
53-
options:
54-
entity_path: 'your-topic'
55-
subscription: 'subscription-name'
56-
token_expiry: 60
57-
receive_mode: 'receive-and-delete'
58-
```
59-
60-
## Stamps
61-
62-
This transport provides 2 stamps:
63-
64-
### AzureReceivedStamp
65-
66-
The `AymDev\MessengerAzureBundle\Messenger\Stamp\AzureReceivedStamp` stamp holds the original message body and an optional deletion URL.
67-
68-
### AzureBrokerPropertiesStamp
69-
70-
The `AymDev\MessengerAzureBundle\Messenger\Stamp\AzureBrokerPropertiesStamp` stamp is used for the [message properties](https://docs.microsoft.com/en-us/rest/api/servicebus/message-headers-and-properties).
71-
It is automatically decoded when consuming a message and is encoded when producing a message if added to the *envelope*.
72-
73-
## Serialization
74-
75-
There is no serializer provided, but here is the expected array structure of an encoded envelope:
76-
77-
- `body`: your plain text message
1+
# Messenger Azure Service Bus Bundle
2+
A **Symfony 4 / 5 / 6** bundle providing a **Symfony Messenger** *transport* for **Azure Service Bus** using the *Azure REST API*.
3+
4+
![Testing](https://github.com/AymDev/MessengerAzureBundle/workflows/Testing/badge.svg)
5+
![Coding Standards](https://github.com/AymDev/MessengerAzureBundle/workflows/Coding%20Standards/badge.svg)
6+
![Bundle installation](https://github.com/AymDev/MessengerAzureBundle/workflows/Bundle%20installation/badge.svg)
7+
[![Latest Stable Version](https://poser.pugx.org/aymdev/messenger-azure-bundle/v)](//packagist.org/packages/aymdev/messenger-azure-bundle)
8+
[![License](https://poser.pugx.org/aymdev/messenger-azure-bundle/license)](//packagist.org/packages/aymdev/messenger-azure-bundle)
9+
10+
## Installation
11+
12+
You only need to install the bundle using **Composer**:
13+
```shell
14+
composer require aymdev/messenger-azure-bundle
15+
```
16+
As it uses [Symfony HttpClient](https://symfony.com/doc/current/http_client.html),
17+
you will need to install a [PSR-18 client](https://symfony.com/doc/current/http_client.html#psr-18-and-psr-17).
18+
Example:
19+
```shell
20+
composer require nyholm/psr7
21+
```
22+
23+
## Configuration
24+
25+
### Transport DSN
26+
27+
Your DSN must respect the following format to build the authentication header for a specific *namespace*:
28+
```
29+
azure://KEY_NAME:KEY_VALUE@NAMESPACE
30+
```
31+
>Where `KEY_NAME` is your **shared access key name**, `KEY_VALUE` is your **shared access key** and `NAMESPACE` is your
32+
>*Azure Service Bus* **namespace**.
33+
34+
### Transport options
35+
36+
Detailed list of transport options:
37+
38+
| Option name | Description | Required | Default value |
39+
| ------------- | ------------- | ----: | ----: |
40+
| `entity_path` | The **topic** or **queue** name. | Yes | |
41+
| `subscription` | The subcription name to consume messages from a **topic**. | Only for *topic consumer transports* | |
42+
| `token_expiry` | [SAS token](https://docs.microsoft.com/en-us/azure/service-bus-messaging/service-bus-sas#generate-a-shared-access-signature-token) validity duration in seconds. | | `3600` |
43+
| `receive_mode` | Set to `peek-lock` to perform a [non destructive read](https://docs.microsoft.com/en-us/rest/api/servicebus/peek-lock-message-non-destructive-read) or to `receive-and-delete` to perform a [destructive-read](https://docs.microsoft.com/en-us/rest/api/servicebus/receive-and-delete-message-destructive-read) | | `peek-lock` |
44+
45+
Example `config/packages/messenger.yaml`:
46+
```yaml
47+
framework:
48+
messenger:
49+
transports:
50+
azure_transport:
51+
dsn: '%env(AZURE_SERVICE_BUS_DSN)%'
52+
serializer: 'App\Messenger\YourAzureSerializer'
53+
options:
54+
entity_path: 'your-topic'
55+
subscription: 'subscription-name'
56+
token_expiry: 60
57+
receive_mode: 'receive-and-delete'
58+
```
59+
60+
## Stamps
61+
62+
This transport provides 2 stamps:
63+
64+
### AzureMessageStamp
65+
66+
The `AymDev\MessengerAzureBundle\Messenger\Stamp\AzureMessageStamp` stamp is added to sent and received messages and
67+
contains:
68+
69+
- the *topic* or *queue* name
70+
- the original sent/received message
71+
- the subscription name for received messages from *topics*
72+
- the delete URL for received messages in `peek-lock` receive mode
73+
74+
### AzureBrokerPropertiesStamp
75+
76+
The `AymDev\MessengerAzureBundle\Messenger\Stamp\AzureBrokerPropertiesStamp` stamp is used for the [message properties](https://docs.microsoft.com/en-us/rest/api/servicebus/message-headers-and-properties).
77+
It is automatically decoded when consuming a message and is encoded when producing a message if added to the *envelope*.
78+
79+
### AzureReceivedStamp
80+
81+
The `AymDev\MessengerAzureBundle\Messenger\Stamp\AzureReceivedStamp` stamp holds the original message body and an optional deletion URL.
82+
>This stamp is deprecated in favor of the AzureMessageStamp and will be removed in v2.
83+
84+
## Serialization
85+
86+
There is no serializer provided, but here is the expected array structure of an encoded envelope:
87+
88+
- `body`: your plain text message
7889
- `headers`: optional HTTP headers (either received from *Azure Service Bus* response or to send to the REST API)
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace AymDev\MessengerAzureBundle\Messenger\Stamp;
6+
7+
use Symfony\Component\Messenger\Stamp\StampInterface;
8+
use Symfony\Contracts\HttpClient\Exception\HttpExceptionInterface;
9+
use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface;
10+
use Symfony\Contracts\HttpClient\ResponseInterface;
11+
12+
/**
13+
* Azure Service Bus stamp added to sent and received messages containing message metadata
14+
*/
15+
class AzureMessageStamp implements StampInterface
16+
{
17+
/** @var string */
18+
private $entityPath;
19+
20+
/** @var string */
21+
private $message;
22+
23+
/** @var null|string */
24+
private $subscriptionName;
25+
26+
/** @var string|null */
27+
private $locationHeader;
28+
29+
/**
30+
* @internal
31+
* @param string $message the original message
32+
* @param string|null $locationHeader optional "Location" response header
33+
*/
34+
public function __construct(
35+
string $entityPath,
36+
string $message,
37+
?string $subscriptionName = null,
38+
?string $locationHeader = null
39+
) {
40+
$this->entityPath = $entityPath;
41+
$this->message = $message;
42+
$this->subscriptionName = $subscriptionName;
43+
$this->locationHeader = $locationHeader;
44+
}
45+
46+
/**
47+
* Create a stamp from an HTTP response in the receiver transport
48+
* @internal
49+
* @throws HttpExceptionInterface|TransportExceptionInterface
50+
*/
51+
public static function createFromResponse(
52+
ResponseInterface $response,
53+
string $entityPath,
54+
?string $subscriptionName
55+
): self {
56+
return new self(
57+
$entityPath,
58+
$response->getContent(),
59+
$subscriptionName,
60+
$response->getHeaders()['location'][0] ?? null
61+
);
62+
}
63+
64+
public function getEntityPath(): string
65+
{
66+
return $this->entityPath;
67+
}
68+
69+
public function getMessage(): string
70+
{
71+
return $this->message;
72+
}
73+
74+
public function getSubscriptionName(): ?string
75+
{
76+
return $this->subscriptionName;
77+
}
78+
79+
public function getLocationHeader(): ?string
80+
{
81+
return $this->locationHeader;
82+
}
83+
}

src/Messenger/Stamp/AzureReceivedStamp.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111

1212
/**
1313
* Azure Service Bus receiver stamp with message metadata
14+
* TODO: remove stamp in v2
15+
* @deprecated AzureReceivedStamp is kept for compatibility purposes. Use AzureMessageStamp instead
1416
*/
1517
class AzureReceivedStamp implements NonSendableStampInterface
1618
{

src/Messenger/Transport/AzureTransport.php

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
namespace AymDev\MessengerAzureBundle\Messenger\Transport;
66

77
use AymDev\MessengerAzureBundle\Messenger\Stamp\AzureBrokerPropertiesStamp;
8+
use AymDev\MessengerAzureBundle\Messenger\Stamp\AzureMessageStamp;
89
use AymDev\MessengerAzureBundle\Messenger\Stamp\AzureReceivedStamp;
910
use Symfony\Component\Messenger\Envelope;
1011
use Symfony\Component\Messenger\Exception\TransportException;
@@ -36,16 +37,26 @@ final class AzureTransport implements TransportInterface
3637
/** @var string */
3738
private $receiveMode;
3839

40+
/** @var string */
41+
private $entityPath;
42+
43+
/** @var string|null */
44+
private $subscriptionName;
45+
3946
public function __construct(
4047
SerializerInterface $serializer,
4148
HttpClientInterface $senderClient,
4249
HttpClientInterface $receiverClient,
43-
string $receiveMode
50+
string $receiveMode,
51+
string $entityPath,
52+
?string $subscriptionName = null
4453
) {
4554
$this->serializer = $serializer;
4655
$this->senderClient = $senderClient;
4756
$this->receiverClient = $receiverClient;
4857
$this->receiveMode = $receiveMode;
58+
$this->entityPath = $entityPath;
59+
$this->subscriptionName = $subscriptionName;
4960
}
5061

5162
/**
@@ -90,6 +101,7 @@ public function get(): iterable
90101
$brokerPropertiesStamp = AzureBrokerPropertiesStamp::createFromResponse($response);
91102
$envelope = $envelope
92103
->with(AzureReceivedStamp::createFromResponse($response))
104+
->with(AzureMessageStamp::createFromResponse($response, $this->entityPath, $this->subscriptionName))
93105
->with($brokerPropertiesStamp)
94106
;
95107

@@ -155,7 +167,11 @@ public function send(Envelope $envelope): Envelope
155167
);
156168
}
157169

158-
return $envelope;
170+
return $envelope->with(new AzureMessageStamp(
171+
$this->entityPath,
172+
$encodedMessage['body'],
173+
$this->subscriptionName
174+
));
159175
}
160176

161177
/**
@@ -187,8 +203,8 @@ private function delete(Envelope $envelope): void
187203
private function getDeleteUri(Envelope $envelope): string
188204
{
189205
// Use delete location URL
190-
/** @var null|AzureReceivedStamp $receivedStamp */
191-
$receivedStamp = $envelope->last(AzureReceivedStamp::class);
206+
/** @var null|AzureMessageStamp $receivedStamp */
207+
$receivedStamp = $envelope->last(AzureMessageStamp::class);
192208

193209
if (null !== $receivedStamp && null !== $receivedStamp->getLocationHeader()) {
194210
return $receivedStamp->getLocationHeader();

src/Messenger/Transport/AzureTransportFactory.php

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,14 @@ public function createTransport(string $dsn, array $options, SerializerInterface
6161
$receiverConfiguration['options']
6262
);
6363

64-
return new AzureTransport($serializer, $senderClient, $receiverClient, $options['receive_mode']);
64+
return new AzureTransport(
65+
$serializer,
66+
$senderClient,
67+
$receiverClient,
68+
$options['receive_mode'],
69+
$options['entity_path'],
70+
$options['subscription']
71+
);
6572
}
6673

6774
/**

0 commit comments

Comments
 (0)