Polyphony was designed to ease the transition from blocking APIs and callback-based API to non-blocking, fiber-based ones. It is important to understand that not all blocking calls can be easily converted into non-blocking calls. That might be the case with Ruby gems based on C-extensions, such as database libraries. In that case, Polyphony's built-in thread pool might be used for offloading such blocking calls.
Some of the most common patterns in Ruby APIs is the callback pattern, in which
the API takes a block as a callback to be called upon completion of a task. One
such example can be found in the excellent
http_parser.rb gem, which is used by
Polyphony itself to provide HTTP 1 functionality. The HTTP:Parser
provides
multiple hooks, or callbacks, for being notified when an HTTP request is
complete. The typical callback-based setup is as follows:
require 'http/parser'
@parser = Http::Parser.new
def on_receive(data)
@parser < data
end
@parser.on_message_complete do |env|
process_request(env)
end
A program using http_parser.rb
in conjunction with Polyphony might do the
following:
require 'http/parser'
require 'polyphony'
def handle_client(client)
parser = Http::Parser.new
req = nil
parser.on_message_complete { |env| req = env }
loop do
parser << client.read
if req
handle_request(req)
req = nil
end
end
end
Another possibility would be to monkey-patch Http::Parser
in order to
encapsulate the state of the request:
class Http::Parser
def setup
self.on_message_complete = proc { @request_complete = true }
end
def parser(data)
self << data
return nil unless @request_complete
@request_complete = nil
self
end
end
def handle_client(client)
parser = Http::Parser.new
loop do
if req == parser.parse(client.read)
handle_request(req)
end
end
end