Back to Articles




Use this process to set up Sidekiq for a Rails app on an AWS Elastic Beanstalk deployment.

References:

Assumptions

  • 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

Prerequisites

  • Redis is required for Sidekiq.  Request sysops to setup Redis on an Amazon host.
    • 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.

In your Rails application

Add sidekiq gem

  • Edit Gemfile and add...

    gem 'sidekiq', '~> 5.2'
  • Update dependencies

    bundle install

Set application to use sidekiq for job queue

  • 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 initializers and configurations

  • 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
     

Add route for sidekiq

  • Edit config/routes.rb and add the following near the top where you mount other engines...

      require 'sidekiq/web'
      mount Sidekiq::Web => '/sidekiq'

Add script to start/restart 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

Add script to give Sidekiq permission to files and directories it needs to access

  • 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
    
    


Add instructions in README for starting sidekiq

  • Edit README.md and add...

    Start Sidekiq in development for processing background jobs (Needs to run at the root of the rails app.)
    
    ```sh
    $ bundle exec sidekiq -d -L log/sidekiq.log -e development
    ```


Debugging Problems

Common Debugging Steps

Check if sidekiq is running...

  • 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

Restart sidekiq

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.

On AWS...

  • To stop...
    • 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
      NOTE 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...  
    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

On DEV machine...

You can use similar commands on your local development machine. On my laptop development environment, I use...

  • To stop...
    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...

    bundle exec sidekiq -d -L log/sidekiq.log -e development

Jobs enqueue but don't process

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.


_app_URL_/sidekiq returns 502 Bad Gateway

Contact sysops.  As a result, some aspect of the machine was made bigger.  Not sure exactly what they did.



  • No labels