-
Notifications
You must be signed in to change notification settings - Fork 0
AWS EB: Set up Sidekiq for Rails app on AWS Elastic Beanstalk
Use this process to set up Sidekiq messaging queue for a Rails app on an AWS Elastic Beanstalk deployment.
References:
- Redis
- Redis - What is id? (AWS documentation)
- Redis vs. Memcached (AWS documentation)
- Amazon ElastiCache for Redit (AWS documentation)
- Redis gem README
- Sidekiq
- Your app has already been setup to run on AWS Elastic Beanstalk.
- Examples show setting up Sidekiq 5.2.5
- Procedure was tested with Ruby 2.5.5 and Rails 5.1.7
- Redis is required for Sidekiq.
- Add Elastic Beanstalk ENV variable REDIS_HOST and set it to the host where Redis is installed. Sysops may have set this already in the process of setting up the Redis host.
Edit Gemfile and add...
gem 'sidekiq', '~> 5.2'
Update dependencies
bundle install
Edit config/environments/development.rb, integration.rb, staging.rb, production.rb and add (or edit) line...
config.active_job.queue_adapter = :sidekiq
Edit config/environments/test.rb and set it to run jobs at the time they are called. Jobs will not run asynchronously.
config.active_job.queue_adapter = :inline
Add config/initializers/sidekiq.rb
config = YAML.load(ERB.new(IO.read(Rails.root + 'config' + 'redis.yml')).result)[Rails.env].with_indifferent_access
redis_conn = { url: "redis://#{config[:host]}:#{config[:port]}/" }
Sidekiq.configure_server do |s|
s.redis = redis_conn
end
Sidekiq.configure_client do |s|
s.redis = redis_conn
end
Add config/sidekiq.yml. This shows adding the default queue. You may want to have more queues depending on your application needs.
---
:queues:
- default
Add config/redis.yml
default:
host: <%= ENV['REDIS_HOST'] || "localhost" %>
port: 6379
db: 0
development:
host: <%= ENV['REDIS_HOST'] || "localhost" %>
port: 6379
db: 1
test:
host: <%= ENV['REDIS_HOST'] || "localhost" %>
port: 6379
db: 2
integration:
host: <%= ENV['REDIS_HOST'] || "localhost" %>
port: 6379
db: 3
staging:
host: <%= ENV['REDIS_HOST'] || "localhost" %>
port: 6379
db: 4
production:
host: <%= ENV['REDIS_HOST'] || "localhost" %>
port: 6379
db: 5
Edit config/routes.rb and add the following near the top where you mount other engines...
require 'sidekiq/web'
mount Sidekiq::Web => '/sidekiq'
Create .ebextensions/sidekiq.config. This script will create two files on the AWS machine: 1. /opt/elasticbeanstalk/hooks/appdeploy/post/50_restart_sidekiq.sh starts up sidekiq on the AWS machine after each deploy, 2. /opt/elasticbeanstalk/hooks/appdeploy/pre/03_mute_sidekiq.sh shuts down sidekiq on the AWS machine just before a deploy
# Sidekiq interaction and startup script
commands:
create_post_dir:
command: "mkdir -p /opt/elasticbeanstalk/hooks/appdeploy/post"
ignoreErrors: true
files:
"/opt/elasticbeanstalk/hooks/appdeploy/post/50_restart_sidekiq.sh":
mode: "000755"
owner: root
group: root
content: |
#!/usr/bin/env bash
. /opt/elasticbeanstalk/support/envvars
EB_APP_DEPLOY_DIR=$(/opt/elasticbeanstalk/bin/get-config container -k app_deploy_dir)
EB_APP_PID_DIR=$(/opt/elasticbeanstalk/bin/get-config container -k app_pid_dir)
EB_APP_USER=$(/opt/elasticbeanstalk/bin/get-config container -k app_user)
EB_SCRIPT_DIR=$(/opt/elasticbeanstalk/bin/get-config container -k script_dir)
EB_SUPPORT_DIR=$(/opt/elasticbeanstalk/bin/get-config container -k support_dir)
. $EB_SUPPORT_DIR/envvars
. $EB_SCRIPT_DIR/use-app-ruby.sh
SIDEKIQ_PID=$EB_APP_PID_DIR/sidekiq.pid
SIDEKIQ_CONFIG=$EB_APP_DEPLOY_DIR/config/sidekiq.yml
SIDEKIQ_LOG=$EB_APP_DEPLOY_DIR/log/sidekiq.log
cd $EB_APP_DEPLOY_DIR
if [ -f $SIDEKIQ_PID ]
then
su -s /bin/bash -c "kill -TERM `cat $SIDEKIQ_PID`" $EB_APP_USER
su -s /bin/bash -c "rm -rf $SIDEKIQ_PID" $EB_APP_USER
fi
. /opt/elasticbeanstalk/support/envvars.d/sysenv
sleep 10
su -s /bin/bash -c "bundle exec sidekiq \
-e $RACK_ENV \
-P $SIDEKIQ_PID \
-C $SIDEKIQ_CONFIG \
-L $SIDEKIQ_LOG \
-d" $EB_APP_USER
"/opt/elasticbeanstalk/hooks/appdeploy/pre/03_mute_sidekiq.sh":
mode: "000755"
owner: root
group: root
content: |
#!/usr/bin/env bash
. /opt/elasticbeanstalk/support/envvars
EB_APP_USER=$(/opt/elasticbeanstalk/bin/get-config container -k app_user)
EB_SCRIPT_DIR=$(/opt/elasticbeanstalk/bin/get-config container -k script_dir)
EB_SUPPORT_DIR=$(/opt/elasticbeanstalk/bin/get-config container -k support_dir)
. $EB_SUPPORT_DIR/envvars
. $EB_SCRIPT_DIR/use-app-ruby.sh
SIDEKIQ_PID=$EB_APP_PID_DIR/sidekiq.pid
if [ -f $SIDEKIQ_PID ]
then
su -s /bin/bash -c "kill -USR1 `cat $SIDEKIQ_PID`" $EB_APP_USER
fi
Create .ebextensions/sidekiq_permissions.config. This script will create one file on the AWS machine: 1. /opt/elasticbeanstalk/hooks/appdeploy/post/51_chmod_logs.sh sets permissions on log files to allow sidekiq to access them
# Set permissions for files accessed by Sidekiq
files:
"/opt/elasticbeanstalk/hooks/appdeploy/post/51_chmod_logs.sh":
mode: "000755"
owner: root
group: root
content: |
#!/usr/bin/env bash
. /opt/elasticbeanstalk/support/envvars
EB_APP_DEPLOY_DIR=$(/opt/elasticbeanstalk/bin/get-config container -k app_deploy_dir)
APP_LOG_DIR=$EB_APP_DEPLOY_DIR/log
SIDEKIQ_LOG=$APP_LOG_DIR/sidekiq.log
case $RACK_ENV in
"integration")
RAILS_LOG=$APP_LOG_DIR/integration.log
;;
"staging")
RAILS_LOG=$APP_LOG_DIR/staging.log
;;
"production")
RAILS_LOG=$APP_LOG_DIR/production.log
;;
esac
touch $SIDEKIQ_LOG
chmod 0664 $SIDEKIQ_LOG
touch $RAILS_LOG
chmod 0664 $RAILS_LOG
Edit README.md and add...
Start Sidekiq in development for processing background jobs (Needs to run at the root of the rails app.)
$ bundle exec sidekiq -d -L log/sidekiq.log -e development
ssh into the AWS machine and execute...
ps aux | grep sidekiq
if sidekiq is running, you will see something like...
webapp 17372 0.8 14.8 1908540 1210232 ? Sl Mar06 7:00 sidekiq 5.2.8 current [0 of 5 busy]
From this, we see that the PID for sidekiq is 17372
This section is not well tested. If you determine anything to be inaccurate or have a better way to handle this, either leave a comment below, or edit the page and make a comment as to what you think is correct, or send the info to elr37 and I will update the page.
To stop (on AWS)...
- stop sidekiq process
- PREREQ get PID for sidekiq using steps above for Check if sidekiq is running...
- SUBSTITUTE actual PID for PID (e.g. 17372)
$ sudo kill _PID_
- delete file holding the sidekiq pid
- SUBSTITUTE the actual location of sidekiq.pid if it is different than what is shown here.
$ find / -name sidekiq.pid 2>/dev/null
/var/app/containerfiles/pids/sidekiq.pid
$ sudo rm /var/app/containerfiles/pids/sidekiq.pid
To start (on AWS)...
- ASSUMES sidekiq is not running already
- SUBSTITUTE the actual environment, i.e. staging or production, for integration, shown here)
bundle exec sidekiq -d -L log/sidekiq.log -e integration -P /var/app/containerfiles/pids/sidekiq.pid -C config/sidekiq.yml
To stop (on DEV machine)...
- PREREQ get PID for sidekiq using steps above for Check if sidekiq is running...
- SUBSTITUTE actual PID for PID (e.g. 17372)
$ sudo kill _PID_
To start (on DEV machine)...
bundle exec sidekiq -d -L log/sidekiq.log -e development
In my case, sidekiq was not actually running. The symptoms were that I could navigate to the sidekiq UI in my app (e.g. app_URL/sidekiq). I could see jobs added to the queue, but they never ran.
When I checked in the terminal whether sidekiq was running, it was not. Once I started sidekiq, the queued jobs began to process.
See info about checking whether sidekiq is running and how to start it under [#common-debugging-steps] above.
Contact sysops. As a result, some aspect of the machine was made bigger. Not sure exactly what they did.