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 request interruptions. 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.

Then I found Goliath, which I found to provide the most flexibility in handling requests. It's built on top of EventMachine, so it uses threads for serving requests, but it can also be run in hybrid mode. However, Goliath is more meant to be used standalone than in tandem with another Rack app.

So I created a Goliath::API subclass that proxies incoming requests to the specified Rack app in a streaming fashion, making it act like a web server for the 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

This will run a single EventMachine process, which by default uses a pool of 20 threads. You can increase the number of threads EventMachine uses:

EventMachine.threadpool_size = 100

You can also spawn multiple EventMachine 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

If you want to report any exceptions that might occur with the Rack app, you can override Goliath::RackProxy#log_exception:

class MyGoliathApp < Goliath::RackProxy
  rack_app MyRackApp

  def log_exception(exception, env)
    super
    Airbrake.notify(exception)
  end
end

License

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