Skip to content

Instantly share code, notes, and snippets.

@niku
Last active July 17, 2025 23:45
Show Gist options
  • Select an option

  • Save niku/44878506db183eeb82d7e14da4f558c7 to your computer and use it in GitHub Desktop.

Select an option

Save niku/44878506db183eeb82d7e14da4f558c7 to your computer and use it in GitHub Desktop.
A small web server built with Ractor that runs Rack apps
require 'etc'
require 'socket'
require 'webrick'
Ractor.make_shareable(WEBrick::Config::HTTP)
Ractor.make_shareable(WEBrick::HTTPUtils::HEADER_CLASSES)
Ractor.make_shareable(WEBrick::HTTPStatus::StatusMessage)
class App
def call(env)
if env["PATH_INFO"] == "/"
[200, {}, ["It works!"]]
else
[404, {}, ["Not Found"]]
end
end
end
class RactorServer
CPU_COUNT = Etc.nprocessors
def self.run(app, **options)
new(app, options).start
end
def initialize(app, options)
@app = app
@options = options
end
def start
port = Ractor::Port.new
dispatcher = Ractor.new(port) do |port|
controller = Ractor::Port.new
todo = Ractor::Port.new
port.send([controller, todo])
loop do
worker = controller.receive
worker.send(todo.receive, move: true)
end
end
controller, todo = port.receive
port.close
workers = CPU_COUNT.times.map do
Ractor.new(@app, @options, controller) do |app, options, controller|
loop do
controller.send(Ractor.current)
s = Ractor.receive
request = WEBrick::HTTPRequest.new(WEBrick::Config::HTTP.merge(RequestTimeout: nil))
request.parse(s)
env = request.meta_vars
status, headers, body = app.call(env)
response = WEBrick::HTTPResponse.new(WEBrick::Config::HTTP)
response.status = status
body.each { |part| response.body << part }
response.send_response(s)
end
end
end
listener = Ractor.new(todo) do |todo|
server = TCPServer.new(8080)
loop do
conn, _ = server.accept
todo.send(conn, move: true)
end
end
loop do
Ractor.select(dispatcher, *workers, listener)
# if the line above returned, one of the dispatcher, the workers or the listener has crashed
end
end
end
Rackup::Handler.register :ractor_server, RactorServer
run App.new
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment