Looking to hire Laravel developers? Try LaraJobs

laravel-asb maintained by paulemich

Description
Azure Service Bus queue driver for Laravel (asb), supporting delay, retry/backoff and dead-lettering. Built on paulemich/azure-service-bus.
Author
Paul Emich
Last update
2026/06/03 12:16 (dev-main)
License
Links
Downloads
0

Comments
comments powered by Disqus

Laravel Azure Service Bus Queue Driver

Latest Version on Packagist Total Downloads License

An Azure Service Bus queue driver for Laravel, registered as the asb connection — the Azure counterpart to Laravel's built-in sqs driver. It plugs straight into Laravel's queue system, so dispatch(), ->delay(), $tries, $backoff, release(), failed(), and dead-lettering all work as you'd expect.

It talks to Service Bus over the REST API (no PHP extensions required) and is built on the framework-agnostic paulemich/azure-service-bus client.

Features

Laravel feature How it maps to Azure Service Bus
dispatch($job) Message sent to the queue (peek-lock on receive)
->delay($seconds) / Queue::later() Native ScheduledEnqueueTimeUtc scheduled delivery
$job->attempts() Native DeliveryCount
Retry after failure Native message abandon (immediately redelivered)
$tries exhausted Honoured by the worker; combine with the queue's MaxDeliveryCount for native dead-lettering
$backoff (delayed retry) Reschedules the message with ScheduledEnqueueTimeUtc, carrying the attempt count forward
queue:clear Drains the queue via destructive receive

Requirements

  • PHP 8.3+
  • Laravel 13+
  • An Azure Service Bus namespace with a queue and a SAS policy that grants Send and Listen (and Manage if you want queue:monitor counts).

Installation

composer require paulemich/laravel-asb

The service provider is auto-discovered and registers the asb queue connector.

Configuration

The package ships with sensible, env-driven defaults that are merged into queue.connections.asb, so the quickest setup is just environment variables:

QUEUE_CONNECTION=asb

# Option A — a full connection string (copy it from the Azure portal):
ASB_CONNECTION_STRING="Endpoint=sb://my-namespace.servicebus.windows.net/;SharedAccessKeyName=RootManageSharedAccessKey;SharedAccessKey=your-key"

# Option B — discrete credentials (use one option or the other):
ASB_NAMESPACE=my-namespace            # short name OR full host (my-namespace.servicebus.windows.net)
ASB_KEY_NAME=RootManageSharedAccessKey
ASB_KEY=your-key

ASB_QUEUE=default                     # the queue (entity) to use
ASB_WAIT=30                           # peek-lock long-poll seconds
# ASB_TTL=3600                        # optional default message TTL (seconds)
# ASB_TOKEN_TTL=3600                  # SAS token lifetime (seconds)

If you prefer to manage everything in config/queue.php (the standard Laravel way), add an explicit connection block:

'connections' => [

    // ...

    'asb' => [
        'driver' => 'asb',
        'connection_string' => env('ASB_CONNECTION_STRING'),
        // or the discrete credentials:
        'namespace' => env('ASB_NAMESPACE'),
        'shared_access_key_name' => env('ASB_KEY_NAME'),
        'shared_access_key' => env('ASB_KEY'),

        'queue' => env('ASB_QUEUE', 'default'),
        'wait' => (int) env('ASB_WAIT', 30),
        'ttl' => env('ASB_TTL') !== null ? (int) env('ASB_TTL') : null,
        'token_ttl' => (int) env('ASB_TOKEN_TTL', 3600),
        'after_commit' => false,
    ],

],

When a connection_string is present it takes precedence; otherwise the discrete namespace / shared_access_key_name / shared_access_key are used. namespace accepts either a short name (my-namespace) or a fully-qualified host (my-namespace.servicebus.windows.net).

Usage

Use it like any other queue connection.

// Dispatch to the default ASB queue
ProcessPodcast::dispatch($podcast);

// Delay (native scheduled delivery)
ProcessPodcast::dispatch($podcast)->delay(now()->addMinutes(10));

// Target a specific queue
ProcessPodcast::dispatch($podcast)->onQueue('media');

// Run a worker against the connection
// php artisan queue:work asb
// php artisan queue:work asb --queue=media

Third-party package jobs work unchanged — the driver only wraps the transport envelope; your job class is serialized into the message payload exactly as with any other driver.

Retries, backoff & dead-lettering

There are two retry paths, and which one runs depends on whether the job asks for a delay:

  • Immediate retry (a job released without a delay, e.g. a thrown exception with no $backoff): the message is abandoned natively. Service Bus increments DeliveryCount and redelivers it. This is fully native — set the queue's MaxDeliveryCount in Azure and exhausted messages are moved to the dead-letter sub-queue automatically.
  • Delayed retry ($backoff, or release($seconds) with a delay): the Service Bus REST API cannot "abandon with a delay", so the driver schedules a fresh copy with ScheduledEnqueueTimeUtc and completes the original. The attempt count is carried forward in a custom message property so attempts() stays correct.

Tip: For jobs that use $backoff, rely on Laravel's $tries / retryUntil() to bound retries rather than the queue's MaxDeliveryCount, since each delayed retry is a freshly scheduled message.

To enable native dead-lettering for the immediate-retry path, set Max Delivery Count on the queue in the Azure portal (Queue → Settings) or via your IaC of choice.

Queue monitoring

Queue::connection('asb')->size() reports active + scheduled messages. pendingSize() and delayedSize() map to the active and scheduled counts respectively. Two methods return fixed values because Service Bus does not expose them over REST:

  • reservedSize() always returns 0 (there is no locked/in-flight count).
  • creationTimeOfOldestPendingJob() always returns null.

Reading counts requires a SAS policy with the Manage claim.

Artisan commands

The package ships a few diagnostic commands for poking at a live queue and seeing exactly what the driver does. They all accept --connection= (default asb) and --queue= (defaults to the connection's configured queue).

# Show message counts: the driver methods (size/pending/delayed/reserved) and
# the raw Service Bus breakdown (active/scheduled/dead-letter/total).
php artisan asb:counts

# Send messages. Generates a JSON probe payload when no body is given.
php artisan asb:send                         # one probe message
php artisan asb:send '{"hello":"world"}'     # a literal body
php artisan asb:send --count=5 --delay=30    # five messages, scheduled 30s out
php artisan asb:send --property=Priority=high --property=Tenant=acme

# Peek-lock receive a single message and print its broker properties, custom
# properties and body. --ack controls settlement: abandon (default), complete, hold.
php artisan asb:receive --wait=10 --ack=complete

# Remove all available messages from the queue.
php artisan asb:purge

Testing

composer install
vendor/bin/pest

The suite uses Orchestra Testbench and mocks the Service Bus client, so no Azure account or network access is needed.

License

The MIT License (MIT). See LICENSE.md.