Skip to content

Instantly share code, notes, and snippets.

@1v
Last active November 12, 2020 20:49
Show Gist options
  • Save 1v/04901ed17202cddfe42d to your computer and use it in GitHub Desktop.
Save 1v/04901ed17202cddfe42d to your computer and use it in GitHub Desktop.
God and Puma configuration

God and Puma configuration

Add to Gemfile:

gem 'puma'
gem 'god'

Run in app folder:

bundle install

Create file /config/puma/development.rb with contents:

daemonize true
bind "unix:///tmp/MyAppDevelopment.sock"
pidfile "tmp/development.pid"

And file /config/puma/production.rb:

daemonize true
bind "unix:///tmp/MyAppProduction.sock"
pidfile "tmp/production.pid"

This files will be loaded autamaticly by puma when environment specified.

Create god config file config.god:

CONFIG_ROOT = File.dirname(__FILE__)

["app1", "app2"].each do |app_name|

  app_root = "#{CONFIG_ROOT}/#{app_name}"

  def generic_monitoring(w, options = {})

    w.start_grace = 20.seconds
    w.restart_grace = 20.seconds
    w.interval = 60.seconds

    w.start_if do |start|
      start.condition(:process_running) do |c|
        c.interval = 10.seconds
        c.running = false
      end
    end

    w.restart_if do |restart|
      restart.condition(:memory_usage) do |c|
        c.above = options[:memory_limit]
        c.times = [3, 5] # 3 out of 5 intervals
      end

      restart.condition(:cpu_usage) do |c|
        c.above = options[:cpu_limit]
        c.times = 5
      end
    end

    w.lifecycle do |on|
      on.condition(:flapping) do |c|
        c.to_state = [:start, :restart]
        c.times = 5
        c.within = 5.minute
        c.transition = :unmonitored
        c.retry_in = 10.minutes
        c.retry_times = 5
        c.retry_within = 2.hours
      end
    end
  end

  ["development", "production"].each do |env|
    God.watch do |w|
      w.name = app_name + "-" + env
      w.group = app_name
      assets = (env == "production") ? "rake assets:precompile --trace RAILS_ENV=production && " : ""
      w.start = "cd #{app_root} && #{assets}puma -e #{env}"
      w.restart = "cd #{app_root} && #{assets}pumactl -P tmp/#{env}.pid restart"
      w.stop = "cd #{app_root} && pumactl -P tmp/#{env}.pid stop"
      w.pid_file = "#{app_root}/tmp/#{env}.pid"

      w.log = "#{app_root}/log/god.log"

      w.behavior(:clean_pid_file)

      generic_monitoring(w, :cpu_limit => 80.percent, :memory_limit => 200.megabytes)
    end
  end
end

Put this file in folder with your apps (app1, app2).

Start god:

god -c config.god

Check status:

god status

For restart all environments:

god restart

For specific:

god restart app1
god restart app2

Same start and stop available.

To stop all processes and god:

god terminate

For debug god run as not deamon:

god -c config.god -D

And watch logs:

tailf log/god.log

For test try to manually stop production:

pumactl -P tmp/production.pid stop

After 10 sec production will work again.

Also we need run god on reboot and if he crashed. So lets add cron job (as luna):

crontab -e

Add in the end of file:

* * * * * /bin/bash -l -c 'cd /home/luna/www/ && god -c config.god' > /dev/null 2>&1

Separate configs for some apps

To add separate config to overall config, add to the end of config.god:

# Load the configs
God.load "/home/luna/www/app1/config/config.god"
God.load "/home/luna/www/app2/config/config.god"

Or for load all configs use:

files = Dir.glob "/home/luna/www/*/config/*.god"

files.each do |f|
  God.load f
end

Test Dir.glob "/home/luna/www/*/config/*.god" in irb to make sure.

See also

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment