Goliath::RackProxy

Allows you to use Goliath as a web server for your Rack app, giving you streaming requests and responses.

Motivation

While developing tus-ruby-server, a Rack application that handles large uploads and large downloads, I wanted to find an appropriate web server to recommend. I needed a web server that supports streaming uploads, allowing the Rack application to start processing the request while the request body is still being received, and that way giving it the ability to save whatever data it received before possible potential request interruption. I also needed support for streaming downloads, sending response body in chunks back to the client.

The only web server I found that supported all of this was Unicorn. However, Unicorn needs to spawn a whole process for serving each concurrent request, which isn't the most efficent use of server resources. It's also difficult to estimate how many workers you need, because once you disable request buffering in the application server, you become vulnerable to slow clients.

Then I came across Goliath, which gave me the control I needed for handling requests. It's built on top of EventMachine, which uses the reactor pattern to schedule work efficiently. The most important feature is that long-running requests won't impact request throughput, as there are no web workers that are waiting for incoming data.

However, Goliath itself is designed to be used standalone, not in tandem with another Rack app. So I created Goliath::RackProxy, which is a Goliath::API subclass that proxies incoming/outgoing requests/responses to/from the specified Rack app in a streaming fashion, essentially making it act like a web server for the Rack app.

Installation

gem "goliath-rack_proxy"

Usage

Create a file where you will initialize the Goliath Rack proxy:

# app.rb
require "goliath/rack_proxy"

class MyGoliathApp < Goliath::RackProxy
  rack_app MyRackApp # provide your #call-able Rack application
end

You can then run the server by running that Ruby file:

$ ruby app.rb

Any command-line arguments passed after the file will be forwarded to the Goliath server (see list of available options):

$ ruby app.rb --port 3000 --stdout

You can scale Goliath applications into multiple processes using Einhorn:

$ einhorn -n COUNT -b 127.0.0.1:3000 ruby app.rb --einhorn

By default Goliath::RackProxy will use a rewindable rack.input, which means the data received from the client will be cached onto disk for the duration of the request. If you don't need the rack.input to be rewindable and want to save on disk I/O, you can disable caching:

class MyGoliathApp < Goliath::RackProxy
  rack_app MyRackApp
  rewindable_input false
end

License

The gem is available as open source under the terms of the MIT License.