I just noticed that some of my listeners do not use the queue I expected them to use. Our team upgraded from Laravel 5.2 to 5.5 a few weeks back, and I guess this is when the problem started happening. There hasn't been much load on the system, so I only discovered it by accident.
Anyway. I used to set the queue name on the listener through a queue method, like so:
public function queue(QueueManager $handler, $method, $arguments): void
{
$handler->connection()->push($method, $arguments, Queue::getNotificationQueue());
}
This approach is not working anymore, so a default queue ends up handling the job instead of the expected notification queue.
So I looked at the documentation https://laravel.com/docs/5.5/events#queued-event-listeners, which states that the name should be set on a queue property on the listener. My problem is that I have the queue name in an environment variable, so I cannot just set it directly as a property, as shown in the documentation and it does not work to set it on the constructor, like so:
protected $queue;
public function __construct()
{
$this->queue = Queue::getNotificationQueue();
}
Does anyone here have an idea of how I can get around this?
Specifically for SQS queues the $queue
property acts a bit weird because it doesn't seem to refer to queues defined in queue.php
, but it expects a full queue url, so even the example in the documentation seems off.
But for dynamic queue names on queued event listeners that for example changes depending on environment, making a custom SqsConnector
and SqsQueue
will be one way to solve your issue.
Here is an example of implementation.
ACMEEventListener.php
class ACMEEventListener implements ShouldQueue
{
public function handle(Event $event): void
{
// I'm going to a custom queue
}
public static function getQueue(): string
{
return 'https://sqs.eu-central-1.amazonaws.com/<account id>/<queue name>';
}
}
CustomSqsConnector.php
use Illuminate\Queue\Connectors\SqsConnector;
use Aws\Sqs\SqsClient;
class CustomSqsConnector extends SqsConnector
{
public function connect(array $config)
{
$sqs = new SqsClient($config);
return new CustomSqsQueue($sqs, $config['queue']);
}
}
CustomSqsQueue.php
class CustomSqsQueue extends \Illuminate\Queue\SqsQueue
{
public function push($job, $data = '', $queue = null)
{
if ($job instanceof CallQueuedListener && method_exists($job->class, 'getQueue')) {
$queue = $job->class::getQueue();
}
return $this->pushRaw($this->createPayload($job, $data), $queue);
}
}
CustomSqsQueueServiceProvider.php
class CustomSqsQueueServiceProvider extends ServiceProvider
{
public function register(): void
{
$this->app->booted(function () {
$this->app['queue']->extend('custom_sqs', function () {
return new CustomSqsConnector;
});
});
}
}
And then in your queue.php
, your default SQS connection driver from sqs
to custom_sqs