Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

kokoshneta's avatar

Queued job runs, but doesn’t execute

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?

0 likes
4 replies
oakydev's avatar

The only thing I've seen is:

$order = Order::find(1234); <- Change this
$order = Order::with('customer')->findOrFail(1234); <- to this
SendConfirmation::dispatch($order)
	->delay(now()->addMinutes(2)); // Testing that the job is inserted in DB
;

To debug your job try a try-catch block.

try {
	Mail::to($this->order->customer->email)
			->send(new OrderConfirmation($this->order));
} catch (\Exception $e) {
	Log::debug($e->getMessage());
}

Hope this helps :D

kokoshneta's avatar

@oakydev The order definitely exists and is found – as evidenced by all the correct details being included in the serialised order object stored in the database.

Wrapping the mail call in a try/catch block might work if it’s the actual email sending that fails – I’ll give it a go tomorrow and see if anything comes of it.

kokoshneta's avatar

@oakydev No dice, unfortunately. Wrapping in a try/catch block didn’t change anything. I’ve even commented out the entire mailing bit so that it only writes a line of plain text to the log, and even that doesn’t work.

kokoshneta's avatar
kokoshneta
OP
Best Answer
Level 27

Oh, sometimes I can really be an idiot…

This Stack Overflow answer provided the clue: I had forgotten that I need to restart the queue worker when my code changes. Obviously nothing new was happening no matter what I changed in the handle() method, because the queue worker was still running on an old version (which must have had an error, but didn’t log anything).

Restarting the queue worker and then running the job again, it immediately worked. 🤦🏽

Running queue:listen instead while debugging now.

Please or to participate in this conversation.