Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How does a Laravel queued job handle a deleted model as input?

What happens if a Laravel queued job is passed an Eloquent model as input, but the model is deleted before the job gets run in the queue?

For example, I am building an eCommerce site with Laravel 5.2 where a customer can enter addresses and payment methods. A payment method belongs to an address. But if a customer tries to delete an address, rather than cascading down and deleting any payment methods that are associated with it, I soft delete the address by marking it as disabled. That way, the payment method can still be used until the customer updates the billing address associated with it.

However, if the payment method is deleted and it references an address that has been soft-deleted, I want to do some garbage collection and delete the address from the database. This doesn't need to happen synchronously, so I wrote a simple queueable job to accomplish this. The handle method looks like this:

public function handle(PaymentMethodRepository $paymentMethodRepository, AddressRepository $addressRepository)
{
    $billingAddress = $paymentMethodRepository->address($this->paymentMethod);

    if ( ! $billingAddress->enabled) {
        $addressRepository->delete($billingAddress);
    }
}

I dispatch this job in the destroy method of the PaymentMethodsController. However, if the payment method passed to the job is deleted from the database before the job gets executed in the queue, will the job fail?

I'm still developing the site so I don't have a server to deploy and test out what happens. I know that the model gets serialized to be put in the queue, but I wonder if an issue would occur when the model is restored to execute the job.

like image 831
Joe Magaro Avatar asked Sep 17 '25 03:09

Joe Magaro


1 Answers

Yes, the job will fail if the "serialized model" is deleted before the job is executed. The model is not really serialized - the job stores the model class and model identifier and fetches the model before execution.

To get around this, you could store the primary key of the model in the job and then when executing the job, check to see if the record exists:

class DeleteAddressJob extends Job implements ShouldQueue
{
    private $addressId;

    public function __construct(int $addressId)
    {
        $this->addressId = $addressId;
    }

    public function handle(AddressRepository $addressRepository)
    {
        $address = $addressRepository->find($this->addressId);

        if (is_null($address)) {
            // Address doesn't exist. Complete job...
            return;
        }

        // Delete the address...
    }
}
like image 144
birderic Avatar answered Sep 19 '25 23:09

birderic