Skip to content
LaravelBlog

laravel/framework: Normalize queue names in SqsQueue::bulk() so events report strings, not enums

LaravelBlogBot
LaravelBlogBot

Contributed by jackbayliss

Part of the framework v13.35.0 release

SQS users who pass backed enums as queue names get a small but welcome consistency fix in this release: SqsQueue::bulk() now normalizes its $queue argument with the framework's enum_value() helper before doing any work. That means the JobQueueing and JobQueued events fired during a bulk push now carry the plain string queue name — 'emails' — instead of the raw enum instance like QueueName::Emails. Every other driver already behaved this way, so this closes the last gap where identical listener code worked on Redis or the database driver but broke on SQS. It's a targeted bug fix with essentially no upgrade surface.

The problem: raw enums leaking into queue events

Laravel accepts backed enums anywhere a queue name is expected:

enum QueueName: string
{
    case Emails = 'emails';
}

Queue::bulk([$jobA, $jobB], queue: QueueName::Emails);

For single pushes, the base Queue::enqueueUsing() helper normalizes the queue name with enum_value() before the job is sent and before the JobQueueing (pre-push) and JobQueued (post-push) events fire. The SQS driver's bulk() override, however, builds and sends its batch payload directly via sendMessageBatch and never passes through that path. The result: on SQS bulk pushes, both events received the enum object itself as $event->queue.

Because backed enums have no __toString() method, any listener that used the value in a string context — logging, str_contains(), cache keys, or strict === comparisons against queue names from config — would either throw an Error or silently fail to match. The reporter hit this while migrating from Redis to SQS: listeners that worked fine on Redis suddenly received raw enums, because only the SQS bulk path skipped normalization.

What the patch changes

The change is a single guard clause at the top of bulk():

public function bulk($jobs, $data = '', $queue = null)
{
    $queue = enum_value($queue);

    // ...
}

enum_value() returns the backing value for any BackedEnum and passes everything else through untouched, so QueueName::Emails becomes 'emails', while string queue names and null (the default queue) behave exactly as before. The pull request also adds a regression test that registers listeners for both events, calls bulk() with a SqsQueueName::Emails enum, and asserts that both events report the normalized string queue name. Per the PR author, normalizing at the entry point is deliberately less invasive than rewiring the SQS bulk implementation onto enqueueUsing(), which the batch-sending path intentionally bypasses.

Why it matters

Queue event listeners are a common integration point — metrics, tracing, per-queue rate limiting, audit logs. Before this fix, a listener like the following worked on every driver except SQS bulk:

use Illuminate\Queue\Events\JobQueued;

Event::listen(JobQueued::class, function (JobQueued $event) {
    Log::info("Job [{$event->id}] queued on [{$event->queue}].");
    // v13.34.0 on SQS: string interpolation of an enum throws an Error
});

After the patch, $event->queue is always a string, so listeners can be strictly typed and driver-agnostic. Follow-up calls like Queue::size($queue), monitoring dashboards keyed by queue name, and comparisons against config('queue.connections.sqs.queue') all behave predictably, regardless of which driver and push method produced the event.

Upgrading from v13.34.0

The impact is minimal:

  • If you pass strings or rely on the default queue, nothing changes at all.
  • If you pass a backed enum to bulk() on SQS, your JobQueueing/JobQueued listeners now receive the string backing value. The only code that needs attention is a listener that explicitly type-checked for the enum:
// Before — only matched on the SQS bulk path
if ($event->queue instanceof QueueName) { /* ... */ }

// After — compare against the backing value
if ($event->queue === QueueName::Emails->value) { /* ... */ } // 'emails'
  • Jobs are still delivered to the same SQS queue; there are no serialization, payload, or worker changes, and no configuration migration is required. Upgrade by pulling the next 13.x patch and you're done.
  • Related but separate: the PR author notes that Queue::size()'s contract doesn't document enum support even though all drivers accept it — that's a follow-up contract cleanup, not part of this change.

Takeaways

  • SqsQueue::bulk() now runs its $queue argument through enum_value(), so enum queue names are normalized before JobQueueing/JobQueued fire.
  • Event payloads on SQS bulk pushes now match every other driver: $event->queue is always a string.
  • Only listeners that intentionally consumed the raw enum need updating; everything else upgrades transparently.
  • No configuration, worker, or payload changes — safe to include in your next routine framework update.
  • Classification: Fix (category 3).

Sources

More from this release

Related Articles