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
Javascript
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:
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.
If you’re not a customer then take a look at our Virtual Hosting, it’s perfect for running your Laravel applications and comes with pm2 pre-installed on the server, along with Node.js, Git and more.