-
Notifications
You must be signed in to change notification settings - Fork 87
Basic Usage
Reel exposes a low-level Ruby API which is great for high-performance applications. If you're looking to use Reel directly as a web server in the same way you would use Unicorn or Puma, you probably want to take a look at Reel::Rack.
Here is a minimal example of how to create a simple "Hello World" web server with Reel:
require 'reel'
Reel::Server::HTTP.run('127.0.0.1', 3000) do |connection|
connection.each_request do |request|
request.respond :ok, "hello, world!"
end
end
Let's look at each of the parts of this and what they do:
require 'reel'
This pulls in the following dependencies:
- Celluloid: a concurrent object framework for Ruby based on the Actor Model. Reel servers are implemented as Celluloid actors. Each one is a concurrent object running in its own thread.
- Celluloid::IO: event-driven I/O for Celluloid. Like EventMachine or Node.js, but uses Fibers in place of callbacks, and can communicate seamlessly with other Celluloid actors. Internally Celluloid::IO uses a nio4r-based reactor that can thunk to high performance system calls like epoll and kqueue which can handle waiting on large numbers of file descriptors from a single thread. This means Reel is a great fit for servers that handle large numbers of idle connections, such as streaming or Websockets servers.
Reel::Server::HTTP is implemented as a Celluloid actor, and uses Celluloid::IO to handle multiple incoming connections from a single thread in the same way that frameworks like EventMachine and Node.js are able to.
Reel::Server::HTTP.run('127.0.0.1', 3000) do |connection|
The #run
method being used here is defined by Celluloid itself. It tells Celluloid to start an actor, then join the main thread to it, effectively letting you run the server actor in the foreground. The arguments passed to the run
method are delegated to Reel::Server::HTTP#initialize
.
Reel's initialize
method is passed the arguments 127.0.0.1
, telling it to bind to localhost, and 3000
, the port to bind to.
Finally, we pass in a block that receives a connection
as a parameter. This is a Reel::Connection object that represents an individual client connected to Reel.
connection.each_request do |request|
It's possible to get more than one request per connection if the client is making use of things like HTTP keepalive or pipelining. In order to support these features of HTTP, we can use #each_request
to iterate through incoming connections.
Each request takes the form of a Reel::Request object. Each request contains all of the stuff you'd ordinarily expect: a verb, a request URI, headers, a body, etc. Since this is just a simple Hello World example, we'll ignore that stuff for now.
- See Requests for more information about handling requests
Now that we have a request, we'd like to respond to it! Since this is a simple Hello World server, we're not going to care about the request at all, and will just respond with "hello world" no matter what request anyone sends us.
To do that, we call the #respond
method of Reel::Request, with some parameters describing the type of response we'd like to send:
request.respond :ok, "hello, world!"
The important thing to know is that using the #respond
method is merely shorthand for constructing a Reel::Response object (you can see where that happens in connection.rb).
This line sends an HTTP/1.1 200 OK response back to the client, with the body "hello, world!"
- See Responses for more information about sending responses