Skip to content

Instantly share code, notes, and snippets.

@eadz
Created July 10, 2023 09:32
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save eadz/b30d3642acc14eacfbe69b61ce0623b1 to your computer and use it in GitHub Desktop.
Save eadz/b30d3642acc14eacfbe69b61ce0623b1 to your computer and use it in GitHub Desktop.
Supervisor - 0 downtime deployments
# No Downtime Deploys
# to setup
# clone your app in ~/app-a and ~/app-b
# use the following caddy server config
# yourdomain.com {
# reverse_proxy * {
# to http://127.0.0.1:4210 http://127.0.0.1:4220
# header_up +Host yourdomain.com
# header_up -X-Forwarded-Host
# health_uri /up
# health_interval 1s
# health_timeout 1s
# }
#}
# To trigger a deploy:
# use github ssh action to `ssh user@server touch redeploy.txt`
#
# To run this in the background, use unix tools...
require "net/http"
HOMEDIR = "/home/myapp".freeze # with no trailing slash
REDEPLOY_FILE = "#{HOMEDIR}/redeploy.txt".freeze
App = Struct.new(:name, :port, :pid) do
def deploy = `cd #{name} && git pull && bundle && ./bin/rails db:migrate`
def kill
return unless pid
Process.kill("SIGTERM", pid)
Process.wait(pid)
self.pid = nil
end
def redeploy
puts "redeploying #{self}"
kill
deploy
self.pid = spawn("./bin/rails server -p #{port}", chdir: "#{HOMEDIR}/#{name}")
puts "waiting for #{self} to come up" until alive?
end
def to_s
"#{name} alive? #{alive?} port: #{port} pid: #{pid}"
end
def alive?
sleep 1
Net::HTTP.get_response(URI("http://localhost:#{port}/up")).code == "200"
rescue Errno::ECONNREFUSED
puts "Connection refused"
false
end
end
apps = [
App.new(name: "app-a", port: "4210"),
App.new(name: "app-b", port: "4220")
]
at_exit { apps.each(&:kill) }
loop do
puts apps
if File.exist?(REDEPLOY_FILE)
apps.each(&:redeploy)
File.delete(REDEPLOY_FILE)
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment