Laravel 13.31 adds interruptible jobs, letting queue workers catch the SIGTERM signal sent during deployments and shut down cleanly instead of aborting a task halfway through. Teams that run long jobs—processing tens of thousands of rows, sending bulk emails, or generating reports—benefit because data stays consistent when a new release rolls out.

Why deployments have been killing jobs

When a new version lands, process managers such as Supervisor, Docker, and Kubernetes tell existing workers to stop by sending SIGTERM, a polite request to terminate. Most workers wait for the current job to finish before exiting. The problem appears when the manager grants only a few seconds to comply. If a job needs minutes, the manager escalates to SIGKILL, killing the process instantly. The job never reaches a consistent state, leaving partially updated records, orphaned files, or duplicate work.

Laravel’s answer: cooperative interruption

Laravel 13.31 introduces a contract named Interruptible that a job class can implement to become aware of the termination request. When SIGTERM arrives, Laravel calls the job’s interrupted() method. The framework does not stop the job automatically; the job must check a flag that Laravel sets and exit on its own. This cooperative model lets developers finish the current loop iteration, roll back partial changes, or write a checkpoint before quitting.

How to make a job interruptible

  1. Implement the contract – add implements Interruptible to the job class definition.
  2. Check the flag inside the work loop – insert a check each iteration to see if the job should stop.
  3. Perform cleanup – in interrupted(), persist any state that will allow the job to resume later, or log the interruption for later analysis.

The biggest trap: don’t use --once

Running the queue worker with php artisan queue:work --once disables signal handling entirely. The worker processes a single job and exits, but it never registers the SIGTERM handler. Consequently, any interruptible job ignores the termination request and is killed mid-process. This pattern shows up in cron-driven containers and one-shot deployments. Fix it by running the daemon mode (php artisan queue:work) whenever you need interruptible jobs.

Watching for interruptions

Laravel fires two events you can hook into:

  • WorkerInterrupted – emitted whenever any worker receives a SIGTERM. Logging this event gives a high-level view of how often deployments interrupt workers.
  • JobInterrupted – emitted only if the current job implements the Interruptible contract. Use this event to trigger job-specific cleanup, such as deleting temporary files or updating a “last processed row” marker.

Listening to these events lets teams build dashboards that show deployment impact and spot jobs that frequently get cut short.

Queue size reporting gets a tweak

The release adds a totalSize() method to the queue manager, returning the total number of pending jobs across all queues. The value is reliable for database-backed and Redis drivers, which report actual counts. Drivers like SQS, Sync, and Beanstalkd still return zero because they don’t expose a count through Laravel’s API. Teams using SQS should keep relying on CloudWatch metrics for queue depth.

What this means for different setups

  • Docker/Kubernetes – the graceful shutdown period can now be used effectively. Extend the termination grace period so jobs have a few seconds to notice the flag and exit cleanly.
  • Supervisor – set stopwaitsecs higher than the time you expect a job to finish after receiving the interrupt flag.
  • Legacy jobs – review any job that runs longer than the manager’s timeout and, where feasible, make it interruptible.

Counter-point: added complexity

The feature does not replace proper timeout configuration. If a job’s loop never checks the interruption flag, the manager will still send SIGKILL. Teams must audit long-running code paths and insert checks at logical breakpoints. Some developers may find the extra boilerplate—implementing a contract and adding flag checks—unappealing for short jobs that already finish within the shutdown window.

Action checklist

  1. Scan deployment scripts for the --once flag and replace it with daemon mode where interruptible jobs are used.
  2. Identify the longest-running jobs (those that touch tens of thousands of rows or run for several minutes) and add the Interruptible contract.
  3. Insert a flag check inside each loop iteration, and move any necessary finalisation code into the interrupted() method.
  4. Hook listeners to WorkerInterrupted and JobInterrupted to collect metrics on how often deployments affect processing.
  5. For Redis or database queues, use totalSize() to monitor backlog; for SQS, keep CloudWatch alarms in place.

Treat deployment-driven shutdowns as a coordinated step rather than an abrupt kill. Laravel 13.31 keeps data consistent and eases the operational headaches of half-finished jobs. The trade-off is a modest increase in code responsibility, but teams that rely on heavy background processing gain a more reliable production environment.