Overview

Note: This article skips over a lot of technical detail on Elastic Beanstalk but is intended to show how to add Supervisord to an existing Laravel application running on AWS Elastic Beanstalk.

Whilst there are other ways to run background tasks on AWS in general, we quickly needed to add a background service to our Elastic Beanstalk Worker instances in order to unlock some of the core functionality that Laravel’s Queue system provides. Previously, the jobs were being pushed from SQS in the following manner:

  • Previously: SQS -> HTTP Request -> Laravel Worker (Elastic Beanstalk Worker)

This push configuration was fine for the most part, but as stated above, we needed to unlock some of the core functionality that Laravel’s Queue system provides, and we really wanted to utilise all the resources (RAM, CPU) we have on our worker instances whilst being able to triple our queue throughput by running multiple workers on a single instance.

  • New Setup: Laravel Worker (Elastic Beanstalk Worker) -> Pull from SQS -> Process Job

1: Adding Supervisord files

Add the following configuration files to your Laravel project. For example, we’ll be adding them in the bin/supervisor directory.

Note: Please configure these files according to your own requirements. The following files are examples and may not be suitable for your use case.

supervisord.conf

[unix_http_server]
file=/var/run/supervisor/supervisor.sock

[supervisord]
logfile=/tmp/supervisord.log
logfile_maxbytes=50MB
logfile_backups=10
loglevel=info
pidfile=/tmp/supervisord.pid
nodaemon=false
minfds=1024
minprocs=200

[supervisorctl]
serverurl=unix:///var/run/supervisor/supervisor.sock

[include]
files = /etc/supervisor/conf.d/*.conf

[inet_http_server]
port = 9000
username = user
password = pw

supervisord_laravel.conf

[program:laravel-worker]
process_name=%(program_name)s_%(process_num)02d
command=/usr/bin/php /var/app/current/artisan queue:work
autostart=true
autorestart=true
stopasgroup=true
killasgroup=true
user=webapp
numprocs=3
redirect_stderr=true
stderr_logfile=/var/log/supervisor_laravel.err.log
stdout_logfile=/var/log/supervisor_laravel.out.log
stopwaitsecs=3600

setup.sh

#!/bin/bash

echo "Supervisor - starting setup"

if [ ! -f /usr/bin/supervisord ]; then
    echo "installing supervisor"
    easy_install supervisor
else
    echo "supervisor already installed"
fi

if [ ! -d /etc/supervisor ]; then
    mkdir /etc/supervisor
    echo "create supervisor directory"
fi

if [ ! -d /etc/supervisor/conf.d ]; then
    mkdir /etc/supervisor/conf.d
    echo "create supervisor configs directory"
fi

# Create directory to store Socket file
if [ ! -d /var/run/supervisor ]; then
    mkdir /var/run/supervisor
    echo "created supervisor socket directory"
fi

cat bin/supervisor/supervisord.conf > /etc/supervisor/supervisord.conf
cat bin/supervisor/supervisord.conf > /etc/supervisord.conf
cat bin/supervisor/supervisord_laravel.conf > /etc/supervisor/conf.d/supervisord_laravel.conf

if ps aux | grep "[/]usr/bin/supervisord"; then
    echo "supervisor is already running (Restart will happen after code deployment)"
else
    echo "starting supervisor"
    /usr/bin/supervisord
fi

# Re-read and update supervisor configuration
/usr/bin/supervisorctl reread
/usr/bin/supervisorctl update

echo "Supervisor Configured!"

2: Setting up Supervisord on AWS Elastic Beanstalk

Once you’ve added all the configuration files and adjusted them to your requirements, you’ll need to add a .ebextensions directory to the root of your Laravel project. This will be used to store your script that will run the setup.sh script above

01_supervisord.config

container_commands:
    install_supervisor:
        command: "bin/supervisor/setup.sh"

This will run the setup.sh script during the deployment of your Laravel application to Elastic Beanstalk.

3: Restarting the Supervisor service on deployment

Finally, you’ll need to add a postdeploy hook to your Laravel project. This will restart the Supervisor service after each deployment. Originally, we had the restart in the setup.sh script, but we ended up encountering race conditions where the Supervisor service would restart before the Laravel application was fully deployed, thus not picking up the new code.

In the .platform/hooks/postdeploy directory, add the following configuration to restart Supervisord.

restart_supervisord.sh

#!/bin/bash

/usr/bin/supervisorctl restart all
echo "Supervisor Restarted"

Conclusion

And that’s it! You should now have Supervisord running on your Elastic Beanstalk Worker instances. You can now run multiple workers on a single instance and unlock the majority of the core functionality that Laravel’s Queue system provides.

If there’s anything you’d like to add or if you have any questions, feel free to reach out to me on LinkedIn or via email at rexchoppers@gmail.com

Credits

  • Massive thank you to Papertrail for allowing me to post this article in the hope it may help others.