Laravel `WithoutOverlapping` Job Middleware and Unexpected `MaxAttemptsExceededException` Errors

I ran into a non-intuitive issue the other day with some queued jobs: after being dispatched, multiple jobs were immediately failing with a MaxAttemptsExceededException error.

This specific job class happens to use the WithoutOverlapping trait so it only runs a single concurrent job per order to prevent race conditions. However, this job can be dispatched multiple times per order for different travelers. Here’s a simplified version of the job:

Can you spot the issue?

When this job was dispatched for order 123 for the only traveler, the queue workers would pick up the job and start processing and everything would be fine.

When this job was dispatched for order 124 for traveler 1 and again for traveler 2, a queue worker would pick up the traveler 1 job and start processing it. Another queue worker would pick up the traveler 2 job, check the middleware, see that another job was already being processed for the order, and fail the job to release it back onto the queue to be tried again later.

Because the first job could take a little while to run, another queue worker would then pick up the traveler 2 job again and again immediately fail it. This would happen until it reached the max number of attempts for the job, and then it would fail throwing a MaxAttemptsExceededException. Depending on how busy the queue workers were, this would happen within a second of the job being dispatched.

It took me a little bit to figure out why jobs were immediately failing with that exception but once I did it made total sense. 🤦🏻‍♂️

The fix? Simple: add the traveler number into the WithoutOverlapping key: new WithoutOverlapping($this->order->id.'-'.$this-travelerNumber).

TL;DR: make sure you use actually-unique WithoutOverlapping keys to prevent immediate MaxAttemptsExceededException after dispatching jobs.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.