   # How to gracefully stop a Laravel CLI command

Last week I was building a console command on top of Laravel that could be running for a long time. It was a long-running process that runs a queue worker. It reads from a queue, does some processing on the data and, then forward it to another queue. And the important bit: the item that is currently processed by the worker should be finished before the worker can quit. Here’s how I did that.

**Date**9 May 2018

Last week I was building a console command on top of [Laravel](https://www.laravel.com/) that could be running for a long time. It was a long-running process that runs a queue worker. It reads from a queue, does some processing on the data and, then forward it to another queue. And the important bit: the item that is currently processed by the worker should be finished before the worker can quit. Here’s how I did that.

### Overview of the CLI command

First let’s start with what the actual worker call looks like. It’s a single while loop:

```php
<?php $worker = new Worker(); while (true) { $worker->work(); }
```

This loop will run forever and each call to Worker::work() does one iteration of the read -> process -> queue sequence.

The entire Laravel CLI command will look like this:

```php
<?php namespace App\Console\Commands; use Illuminate\Console\Command; class MyWorker extends Command { protected $signature = 'my-worker'; protected $description = 'Demonstration worker that gracefully stops on exit'; /** * Execute the console command. * * @return void */ public function fire() { $this->info('Worker started'); $worker = new Worker(); while (true) { $worker->work(); } } } 
```

### Handling a CLI command’s exit signals

Say we run this command using php artisan my-worker and we want to stop it, there are two common ways to do so:

1. CTRL+C on the terminal — This will send an interrupt signal (SIGINT) to the process
2. Run kill \[process id\] – This will send a termination signal (SIGTERM) to the process

What we need to do is make our script so that it receives these signals and let it break out of our while loop when one occurs. To handle these signals in PHP we need to do the following:

1. Depending on your PHP version:
    1. PHP 7.0 and before: Configure our PHP script to handle so-called “ticks”. Without this we can’t listen to the signals.
    2. PHP 7.1 and later: enable async pcntl signals
2. Set handler function to SIGINT and SIGTERM.
3. Tell the loop to stop when the signals are received

Let’s start with how we can stop the while loop. First, we need a variable that tells whether or not the loop should be running. We can create a class-level field for this called run and we set it to true by default. When set to false, the while loop will stop running and the program is stopped.

Then we need to tell PHP to handle ticks using declare(ticks = 1), and register two signal handlers using pcntl\_signal().

Update 13–11–2018: on PHP 7.1 and later it’s more efficient to enable asyncronous signal handling by calling pcntl\_async\_signals(true) instead of declare(ticks = 1).

See the full code below:

```php
<?php namespace App\Console\Commands; use Illuminate\Console\Command; class MyWorker extends Command { protected $signature = 'my-worker'; protected $description = 'Demonstration worker that gracefully stops on exit'; private $run = true; public function fire() { // PHP 7.0 and before can handle asynchronous signals with ticks declare(ticks=1); // PHP 7.1 and later can handle asynchronous signals natively pcntl_async_signals(true); pcntl_signal(SIGINT, [$this, 'shutdown']); // Call $this->shutdown() on SIGINT pcntl_signal(SIGTERM, [$this, 'shutdown']); // Call $this->shutdown() on SIGTERM $this->info('Worker started'); $worker = new Worker(); while ($this->run) { $worker->work(); } $this->info('Worker stopped'); } public function shutdown() { $this->info('Gracefully stopping worker...'); // When set to false, worker will finish current item and stop. $this->run = false; } }
```

### Conclusion

We’ve learned to handle process signals in a Laravel CLI command and in PHP in general. With the help of pcntl\_signal and a shutdown function we took control of how our PHP script exits, giving the ability to clean up what’s going on in the script.

[Back to overview](/en/events-publications)  Link copied to clipboard

### Control Long-Running Processes

Need reliable background workers in Laravel? Dawn Technology builds robust, predictable systems.

<a id="subscribe"></a>## Curious about our latest updates?

Stay up-to-date in the digital landscape with our newsletter. Enrol and get the latest updates in your mail