I haven’t worked with Laravel queues before, so I’m quite new.
For a webshop, I have certain tasks that I would like to queue, such as sending email confirmations to users when their order is complete. The idea is to make a job that sends the email (via Mailgun), then dispatch that job from the function that converts their cart into a processed order and shows the user their receipt. Pretty straightforward.
Going by the docs on queues, I’ve set up a single connection (database driver) and a single queue. I’ve run the database migration for queues. I’ve started the queue:work process on the server; it remains running.
I’ve created a job file App\Jobs\Orders\SendConfirmation, which currently looks like this (with a Log call at the beginning to check that the method is actually called):
class SendConfirmation implements ShouldQueue {
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
public function __construct(public Order $order) { }
public function handle() {
Log::channel('debug')->debug('SendConfirmation dispatched');
Mail::to($this->order->customer->email)
->send(new OrderConfirmation($this->order))
;
}
}
If I send the mail directly from a controller, it works exactly as intended: the email arrives and looks as it should.
But the goal is of course to replace the call to Mail::to()->send() in the controller with this:
$order = Order::find(1234);
SendConfirmation::dispatch($order)
->delay(now()->addMinutes(2)); // Testing that the job is inserted in DB
;
That also appears to work… sort of. In the terminal window on the server, I see messages like this:
2022-11-25 00:27:49 App\Jobs\Orders\SendConfirmation ................. RUNNING
2022-11-25 00:27:49 App\Jobs\Orders\SendConfirmation ........... 159.04ms DONE
So it’s definitely getting the job and executing it. But no email is sent (or appears in the Mailgun logs), and nothing is logged to the debug channel (nor to the general error channel as I’d expect if something threw an exception along the way).
With the delay(), I can confirm that the job looks right in the database:
id queue payload attempts reserved_at available_at created_at
---- --------- ----------- ---------- ------------- -------------- ------------
9 default [payload] 0 NULL 1669337149 1669337029
The payload looks like this:
{
"uuid": "e27c23e8-7e8e-4cf5-b39d-eade84fd74aa",
"displayName": "App\Jobs\Orders\SendConfirmation",
"job": "Illuminate\Queue\CallQueuedHandler@call",
"maxTries": null,
"maxExceptions": null,
"failOnTimeout": false,
"backoff": null,
"timeout": null,
"retryUntil": null,
"data": {
"commandName": "App\Jobs\Orders\SendConfirmation",
"command": [serialised command]
}
}
When unserialised, the command contains an accurate representation of my $order object:
App\Jobs\Orders\SendConfirmation {
+order: App\Models\Order {
id: 1234,
customer_id: 4321,
cart_id: 123,
[more attributes left out for brevity]
created_at: "2022-11-23 01:43:33",
updated_at: "2022-11-23 01:43:33",
}
This section in the docs say that,
If your queued job accepts an Eloquent model in its constructor, only the identifier for the model will be serialized onto the queue. When the job is actually handled, the queue system will automatically re-retrieve the full model instance and its loaded relationships from the database.
This doesn’t seem to be the case: $order is an Eloquent model, but the full object is serialised, not just its identifier. Not sure if that means anything at all.
How can I debug this? How can I tell what’s going wrong in an asynchronous queue job when nothing gets written to any logs, but nothing happens either?