Skip to content

Instantly share code, notes, and snippets.

@mvastola
Created January 16, 2016 02:06
Show Gist options
  • Save mvastola/60e490aa83a6b3735b73 to your computer and use it in GitHub Desktop.
Save mvastola/60e490aa83a6b3735b73 to your computer and use it in GitHub Desktop.
#!/usr/bin/env ruby
require 'bundler/inline'
gemfile do
source 'https://rubygems.org'
gem 'passenger', '~> 5.0.x'
end
require 'timeout'
require 'net/http'
require 'bundler/cli'
require 'bundler/cli/install'
# The following module courtesy @tylergannon (license TBD) via https://gist.github.com/tylergannon/7690997
module Net
# Overrides the connect method to simply connect to a unix domain socket.
class SocketHttp < HTTP
attr_reader :socket_path
# URI should be a relative URI giving the path on the HTTP server.
# socket_path is the filesystem path to the socket the server is listening to.
def initialize(uri, socket_path)
@socket_path = socket_path
super(uri)
end
# Create the socket object.
def connect
@socket = Net::BufferedIO.new UNIXSocket.new socket_path
on_connect
end
# Override to prevent errors concatenating relative URI objects.
def addr_port
File.basename(socket_path)
end
end
end
require 'phusion_passenger'
PhusionPassenger.locate_directories
PhusionPassenger.require_passenger_lib 'standalone/main'
class PassengerApp
attr_reader :log
def initialize(rackup_contents)
@tmpdir = Dir.mktmpdir
ObjectSpace.define_finalizer(self) do
FileUtils.remove_entry @tmpdir if File.exists?(@tmpdir)
end
@files = Hash.new do |h, k|
h[k] = File.join(@tmpdir, k.to_s).freeze
end
File.write @files['Gemfile'], <<-EOF
source 'https://rubygems.org'
gem 'rack'
gem 'airbrake', :github => 'Partyista/airbrake', :branch => 'master'
EOF
Dir.chdir @tmpdir
File.write(@files['config.ru'], rackup_contents)
Bundler::CLI::Install.new({}).run
@ran = false
@threads = {}
end
def run!
return false if @ran
@ran = true
args = [
@tmpdir,
'--no-install-runtime',
'--no-compile-runtime',
'--rackup', @files['config.ru'],
'--log-file', @files[:log],
'--pid-file', @files[:pid],
'--socket', @files[:socket],
'--min-instances', '0',
'--log-level', '1',
'--max-pool-size', '1',
'--engine', 'builtin'
]
@threads[:server] = Thread.new do
Dir.chdir @tmpdir
$stdout = File.open('/dev/null', 'w')
PhusionPassenger::Standalone.run!(['start', *args])
end
sleep 0.5 until File.exists?(@files[:socket])
@threads[:requester] = Thread.new do
begin
Timeout::timeout(10) do
http = Net::SocketHttp.new('/', @files[:socket])
resp = http.request_get('/')
puts "Server replied with status code #{resp.code}."
end
rescue Timeout::Error
puts "Request to server timed out."
end
end
@threads[:requester].join
if File.exists?(@files['pid.lock'])
PhusionPassenger::Standalone.run!(['stop', '--pid-file', @files[:pid]])
end
@threads[:server].join(10) if @threads[:server] && @threads[:server].alive?
pid = File.read(@files[:pid]) if File.exists?(@files[:pid])
Process.kill('TERM', pid) if pid && @threads[:server].alive?
if pid && Process.kill(0, pid)
warn 'Passenger still alive!!!'
Process.kill('KILL', pid)
end
@log = File.read(@files[:log]).freeze
FileUtils.remove_entry @tmpdir
@tmpdir = nil
true
end
end
# Sample Test
rackup = <<-EOF
require 'rubygems'
require 'bundler/setup'
Bundler.require(:default)
Airbrake.configure do |c|
c.project_id = 01234567
c.project_key = 'abcdef0123456789'
end
raise 'test'
EOF
test_app = PassengerApp.new rackup
test_app.run!
puts test_app.log
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment