require 'puma/plugin'
require 'redis'

# How to stop Puma on Heroku
# - You can't use normal methods because the dyno is not accessible
# - There's no file system, no way to send signals
# but ...
# - You can use Redis or Memcache; any network distributed key-value
#   store

# 1. Add this plugin to your 'lib' directory
# 2. In the `puma.rb` config file add the following lines
#    === Plugins ===
#    require './lib/puma/plugin/redis_stop_puma'
#    plugin 'redis_stop_puma'
# 3. Now, when you set the redis key "puma::restart::web.1", your web.1 dyno
#    will restart
# 4. Sniffing the Heroku logs for R14 errors is application (and configuration)
#    specific. I use the Logentries service, watch for the pattern and the call
#    a webhook back into my app to set the Redis key. YMMV

# You can test this locally by setting the DYNO environment variable when
# when starting puma, e.g. `DYNO=pants.1 puma`

Puma::Plugin.create do
  def start(launcher)

    hostname = ENV['DYNO']
    return unless hostname

    redis = Redis.new(url: ENV.fetch('REDIS_URL', nil))
    return unless redis.ping == 'PONG'

    in_background do
      while true
        sleep 2
        if message = redis.get("puma::restart::#{hostname}")
          redis.del("puma::restart::#{hostname}")
          $stderr.puts message
          launcher.stop
          break
        end
      end
    end
  end
end
