Skip to content

Instantly share code, notes, and snippets.

@kuboon
Last active October 31, 2016 09:41
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 kuboon/724834954d3345798054 to your computer and use it in GitHub Desktop.
Save kuboon/724834954d3345798054 to your computer and use it in GitHub Desktop.
run Rails app as DRb server and access it from CGI process
#!ruby
require 'drb/drb'
require 'logger'
require "rack"
require 'rack/rewindable_input'
module Dispatch
RAILS_ENV = 'staging'
DRUBY_URI = "druby://localhost:13141"
LOCKFILE = "../tmp/pids/dispatch.pid"
LOGGER = Logger.new('../log/dispatch.log')
class CGIHandler
def initialize(app)
@app = app
end
def call(env, stdin, stdout)
env.update(Rack::SCRIPT_NAME => '', # clear
"rack.version" => Rack::VERSION,
"rack.input" => stdin,
"rack.multithread" => false,
"rack.multiprocess" => true,
"rack.run_once" => true,
"rack.url_scheme" => ["yes", "on", "1"].include?(ENV["HTTPS"]) ? "https" : "http"
)
LOGGER.info "#{DRb.uri} call rack"
status, headers, body = @app.call(env)
LOGGER.info "#{DRb.uri} status: #{status}"
begin
stdout.print "Status: #{status}\r\n"
send_headers stdout, headers
send_body stdout, body
ensure
body.close if body.respond_to? :close
end
end
private
def send_headers(stdout, headers)
headers.each { |k, vs|
vs.split("\n").each { |v|
stdout.print "#{k}: #{v}\r\n"
}
}
stdout.print "\r\n"
stdout.flush
end
def send_body(stdout, body)
body.each { |part|
stdout.print part.to_str
stdout.flush
}
end
end
class << self
def main
spawn_server unless server_alive?
$stdin.binmode
DRb.start_service
cgi_handler = DRbObject.new_with_uri(DRUBY_URI)
LOGGER.info "#{DRb.uri} call cgi_handler"
cgi_handler.call(ENV.to_h, Rack::RewindableInput.new($stdin), $stdout)
LOGGER.info "#{DRb.uri} done"
rescue => e
puts "Content-Type: text/plain\nStatus: 500\n\n#{e}"
puts e.backtrace
LOGGER.error ([e] + e.backtrace).join("\n")
end
private
def server_alive?
return false unless File.exist?(LOCKFILE)
return true if process_alive? File.read(LOCKFILE).to_i
File.delete(LOCKFILE)
false
end
def process_alive?(pid)
Process.getpgid( pid )
true
rescue Errno::ESRCH
false
end
def spawn_server
File.open(LOCKFILE, "w") do |f|
if f.flock(File::LOCK_EX | File::LOCK_NB)
f.puts fork { start_service }
sleep 5
else
LOGGER.error("lock failed")
end
end
end
def start_service
$stdout.reopen("/dev/null", "w")
$stderr.reopen("/dev/null", "w")
LOGGER.info 'starting server..'
DRb.start_service(DRUBY_URI, cgi_handler)
LOGGER.info 'started server'
DRb.thread.join
rescue => e
LOGGER.error ([e] + e.backtrace).join("\n")
end
def cgi_handler
ENV['RAILS_ENV'] = RAILS_ENV
require '../config/environment'
CGIHandler.new(Rails.application)
end
end
end
Dispatch.main
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ dispatch.rb.cgi/$1 [QSA,L]
@zdavatz
Copy link

zdavatz commented Oct 31, 2016

Thank you for sharing this!

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