The problem

You’re moving your app from development to production and you need to make sure you queued Laravel jobs run, even after your server (or your provider’s server) has been rebooted.

On dev you might have been running:

nohup php artisan queue:work --daemon > queue.log &

from a shell, or maybe just running artisan inside a screen session, but neither of those will cut it in prod, they’re just not reliable enough – what happens if the php process is killed?

What do Laravel recommend?

The Laravel docs recommend that you use supervisor, but the problem with supervisor is that if you make even minor changes you need root level server access which means you need to involve either your server admins or your hosting provider each time, which is far from ideal.  Even with your own server you don’t want all your developers having that level of access.

The solution

Enter PM2

This is where PM2 comes in to it’s own, although originally designed as a process manager for Node.js applications it isn’t limited to them.  PM2 only needs your provider or server admins to run a single command for you, once, to tell PM2 to start you job list when the server starts – and you can avoid involving them at all if you want, although it’s better to involve them.  After that you can setup your jobs as you wish without any involvement from your server admins.

PM2 does make use of Node.js, which is probably the only downside, although most modern development workflows make use of Node.js somewhere these days so the chances are you already need to use it and it’s already available on your server. 

Installing PM2

Globally (available to all users)

npm install pm2 -g

To a project

npm install pm2

Adding to your path

To make things easier, you’ll want to add the pm2 executable to your shell’s path variable, otherwise you’re going to have to use the full path to the pm2 binary every time and that’s going to get really tiresome.  The path you use is going to depend on your installation method.

Globally installed

It may be that the pm2 executable is already in your path, if so, you don’t need to do anything, if it isn’t then you’ll need to ask your provider/server admin what the path to the pm2 executable is.  For example, on our servers it would be something like:

/opt/plesk/node/17/bin/pm2

Which means we’d want to add a line like this to our .bash_profile (other shells are available):

export PATH=/opt/plesk/node/17/bin:$PATH

The quick way to do that would be run this in your shell:

echo "export PATH=/opt/plesk/node/17/bin:\$PATH" >> ~/.bash_profile

source ~/.bash_profile

This will add it to your bash shell profile, and reload the profile so it works right away.

You should now be able to run the pm2 command and see the help output.

Installed to a project

If you’ve installed PM2 locally then you’re going to need to find the path to it.  Assuming you’re still in the root of your project, the chances are the path to the pm2 executable is:

./node_modules/pm2/bin/pm2

If running the above gives you the help output then we’re in the right place, if not, you’ll need to have a look around and find the path to the pm2 executable.

If that is the correct location then we’ll want to add it to the path on our shell to make life easier.  Which means for bash shell (others are available) we’d want to add a line like this to our .bash_profile:

export PATH=/full/path/to/project-directory/node_modules/pm2/bin:$PATH

The quick way to do that would be run this in your shell (assuming you’re still in the same project directory):

echo "export PATH=`pwd`/node_modules/pm2/bin:\$PATH" >> ~/.bash_profile

source ~/.bash_profile

This will add it to your bash shell profile, taking care of working out the full path for you, and reload the profile so it works right away.

You should now be able to run the pm2 command and see the help output.

A crash course in using PM2

Configuring your “app”

You can either use a Javascript configuration file or YAML, we’ll show you how to use both.

We’re going to configure the Laravel Queue Worker only in this file (you can add multiple apps to a single file if you wish).

YAML

Copy to Clipboard

Javascript

Copy to Clipboard

Most of the configuration is self explanatory:

  • App name – name: laravel-queue-worker
  • Fork a new process – exec_mode: fork
  • Create 3 instances – instances: 3
  • Use PHP – interpreter: php
  • Run artisan – script: artisan
  • Use the following arguments to artisan – args: queue:work –timeout=0 –sleep=1 –tries=1

Args is where we configure the Laravel queue worker, we’re using queue:work rather than queue:listen, so each job is its own process.  We’re disabling timeouts and each job gets a single try.  You might be tempted to add –once, but don’t, it won’t work as the process(es) will die if there are no jobs available and PM2 will think that the app is failing due to all instances failing at startup.

Add to PM2

Save your configuration to a file:

  • laravel-queue-worker.yml (for the YAML)
  • laravel-queue-worker.config.js (for the Javascript)

Now you need to run:

pm2 start laravel-queue-worker.yml

or

pm2 start laravel-queue-worker.config.js

followed by

pm2 save

Check what apps are running

pm2 ls

Monitoring your apps

pm2 monit

press q to quit

Checking logs

pm2 logs laravel-queue-worker

press Ctrl + c to quit.

You can also miss off the app name to view logs from all configured apps.

Restarting / Stopping

pm2 restart laravel-queue-worker

pm2 stop laravel-queue-worker

Deleting

pm2 delete laravel-queue-worker

Automatic startup

This first method requires your provider/server admins to run the command output by PM2 to add your instance of it to the server startup.  If you can’t do that, then check out the alternative method.

pm2 startup

If this gives you an error such as: [PM2][ERROR] Init system not found then the server is probably running CloudLinux, so you should run:

pm2 startup systemd

or if you’re using CloudLinux 6:

pm2 startup centos6

This will give you output similar to:

sudo env PATH=$PATH:/opt/plesk/node/17/bin /opt/plesk/node/17/lib/node_modules/pm2/bin/pm2 startup systemd -u your-username --hp /var/www/vhosts/your-username

That the server admin needs to run.

An alternative method

If you can’t get your server admins to run PM2 for you, then there is an alternative method you can try using cron, some versions allow you to use the special keyword @reboot instead of setting a date and time for a job to run at.  Using this we can run the PM2 startup when the server starts using our own startup script:

Copy to Clipboard

Save the file in your project directory as pm2_startup.sh, make it executable:

chmod +x pm2_startup.sh

and add the following line to your crontab:

@reboot /path/to/pm2_startup.sh

replacing /path/to/pm2_statup.sh with the correct path to the script.  The easiest way to do this is to open your systems crontab editor:

crontab -e

Which will open an editor (possibly vim) to allow you to input the above line.  How to use the editor depends on what your system default is, if there’s little else on screen then it’s probably vim and you can find a cheatsheet here for it: https://devhints.io/vim

Further help

As always, if you’re a customer and you need some further help with this, then let us know, we’re here to help.