aymdev/messenger-azure-bundle
composer require aymdev/messenger-azure-bundle nyholm/psr7
messenger.yaml:
framework:
messenger:
transports:
azure_queue:
dsn: '%env(AZURE_SERVICE_BUS_DSN)%'
options:
entity_path: 'your-queue-name'
AZURE_SERVICE_BUS_DSN=azure://KEY_NAME:KEY_VALUE@NAMESPACE
use Symfony\Component\Messenger\MessageBusInterface;
$bus->dispatch(new YourMessage());
use Symfony\Component\Messenger\Attribute\AsMessageHandler;
#[AsMessageHandler]
public function __invoke(YourMessage $message)
{
// Handle message
}
php bin/console messenger:consume azure_queue -vv
transports:
azure_topic:
dsn: '%env(AZURE_SERVICE_BUS_DSN)%'
options:
entity_path: 'your-topic'
subscription: 'your-subscription'
$bus->dispatch(new YourMessage());
AymDev\MessengerAzureBundle\Serializer\AzureSerializer):
use AymDev\MessengerAzureBundle\Serializer\AzureSerializer;
class YourAzureSerializer extends AzureSerializer
{
public function encode(array $data): string
{
return json_encode($data, JSON_THROW_ON_ERROR);
}
public function decode(string $data): array
{
return json_decode($data, true, 512, JSON_THROW_ON_ERROR);
}
}
messenger.yaml:
transports:
azure_transport:
serializer: 'App\Serializer\YourAzureSerializer'
AzureBrokerPropertiesStamp):
use AymDev\MessengerAzureBundle\Messenger\Stamp\AzureBrokerPropertiesStamp;
$stamp = new AzureBrokerPropertiesStamp([
'CustomProperty' => 'value',
'TimeToLive' => 3600.0, // Must be float (seconds)
]);
$bus->dispatch(new YourMessage(), [$stamp]);
DelayStamp (converted to ScheduledEnqueueTimeUtc):
use Symfony\Component\Messenger\Stamp\DelayStamp;
$bus->dispatch(new YourMessage(), [new DelayStamp(3600)]);
console.error event):
use AymDev\MessengerAzureBundle\Messenger\Exception\SerializerDecodingException;
use Symfony\Component\Console\Event\ConsoleErrorEvent;
$eventDispatcher->addListener(ConsoleErrorEvent::class, function (ConsoleErrorEvent $event) {
if ($event->getError() instanceof SerializerDecodingException) {
$stamp = $event->getError()->getEnvelope()->all()[AzureMessageStamp::class];
// Log topic/queue, subscription, and original message
}
});
%env(AZURE_SERVICE_BUS_DSN)% with .env files for different environments (dev/staging/prod)..env.prod:
AZURE_SERVICE_BSN=azure://PROD_KEY_NAME:PROD_KEY_VALUE@PROD_NAMESPACE
use Symfony\Component\Messenger\Attribute\AsMessageHandler;
use Symfony\Component\Messenger\Exception\RetryException;
#[AsMessageHandler]
public function __invoke(YourMessage $message)
{
if ($someFailure) {
throw new RetryException('Failed to process', 3); // Retry 3 times
}
}
use AymDev\MessengerAzureBundle\Messenger\Stamp\AzureMessageStamp;
#[AsMessageHandler]
public function __invoke(YourMessage $message, AzureMessageStamp $stamp)
{
$this->logger->info('Processing message from topic: '.$stamp->getEntityPath());
}
use AymDev\MessengerAzureBundle\Transport\AzureTransport;
$transport = $this->createMock(AzureTransport::class);
$transport->method('send')->willReturn(new Envelope(new YourMessage()));
$this->container->set(AzureTransport::class, $transport);
DSN URL Encoding
KEY_NAME/KEY_VALUE break URL parsing.$dsn = str_replace(':', '%3A', 'azure://key:name@namespace');
%2F for /, %3A for :, etc.TimeToLive Must Be Float
TimeToLive broker property must be a float (seconds), not an integer.$stamp = new AzureBrokerPropertiesStamp(['TimeToLive' => 3600.0]);
SAS Token Expiry
token_expiry: 3600 (1 hour) may cause auth failures if messages take longer to process.Peek-Lock vs. Receive-and-Delete
peek-lock mode requires manual deletion of messages (via AzureMessageStamp::getDeleteUrl()).#[AsMessageHandler]
public function __invoke(YourMessage $message, AzureMessageStamp $stamp)
{
try {
// Process message
} finally {
if ($stamp->getDeleteUrl()) {
$this->httpClient->request('DELETE', $stamp->getDeleteUrl());
}
}
}
DateTime Timezone Mismatch
AzureBrokerPropertiesStamp may deserialize DateTime objects with incorrect timezones.$stamp = new AzureBrokerPropertiesStamp(['ScheduledEnqueueTimeUtc' => new \DateTime('+1 hour', new \DateTimeZone('UTC'))]);
Enable HTTP Client Logging
config/packages/dev/messenger.yaml:
transports:
azure_transport:
options:
http_client:
logger: true
php bin/console messenger:consume azure_transport -vv
Inspect Raw Azure Responses
use Symfony\Component\HttpClient\Middleware\LoggerMiddleware;
$client = HttpClient::create([
'middlewares' => [
new LoggerMiddleware(Logger::class),
],
]);
Validate SAS Tokens
use AymDev\MessengerAzureBundle\Transport\AzureTransport;
$transport = new AzureTransport($dsn, $options);
$token = $transport->generateSasToken();
// Verify token works in Azure Portal or Postman
Custom Stamps
AzureBrokerPropertiesStamp for additional Azure-specific metadata:
class CustomAzureStamp extends AzureBrokerPropertiesStamp
{
public function __construct(array $properties, private string $customField)
{
parent::__construct($properties);
}
public function getCustomField(): string
{
return $this->customField;
}
}
Transport Decorators
AzureTransport to add pre/post-processing:
use AymDev\MessengerAzureBundle\Transport\AzureTransportInterface;
class
How can I help you explore Laravel packages today?