Class: Raptor::Server
- Inherits:
-
Object
- Object
- Raptor::Server
- Defined in:
- lib/raptor/server.rb,
sig/generated/raptor/server.rbs
Overview
High-performance HTTP server that accepts connections and dispatches them.
Server manages the main accept loop, handling incoming client connections from bound sockets. It uses IO.select for efficient polling and implements automatic load balancing by checking reactor backlog before accepting connections, providing natural backpressure based on system capacity.
Supports TCP, Unix domain, and SSL listeners transparently. TCP_NODELAY is applied only to TCP sockets, and SSL handshakes are performed synchronously before the connection is dispatched.
For HTTP/1.1 connections the first request is parsed inline on the server thread and dispatched directly to the thread pool, falling back to the reactor only when more data is needed. For HTTP/2 connections (negotiated via ALPN) the server sends initial SETTINGS and registers the connection with the reactor for frame processing through the ractor pool.
Constant Summary collapse
- HTTP_SCHEME =
"http"- HTTPS_SCHEME =
"https"- H2_PROTOCOL =
"h2"
Instance Method Summary collapse
-
#accept_connection(listener, reactor) ⇒ void
Accepts a connection from the given listener and dispatches it.
-
#initialize(binder, reactor, thread_pool, request) ⇒ Server
constructor
Creates a new Server instance.
-
#run ⇒ Thread
Starts the server's main accept loop in a new thread.
-
#shutdown ⇒ void
Gracefully shuts down the server.
Constructor Details
#initialize(binder, reactor, thread_pool, request) ⇒ Server
Creates a new Server instance.
55 56 57 58 59 60 61 |
# File 'lib/raptor/server.rb', line 55 def initialize(binder, reactor, thread_pool, request) @binder = binder @reactor = reactor @thread_pool = thread_pool @request = request @running = AtomicBoolean.new(true) end |
Instance Method Details
#accept_connection(listener, reactor) ⇒ void
This method returns an undefined value.
Accepts a connection from the given listener and dispatches it.
For SSL connections with h2 negotiated via ALPN, the server sends initial SETTINGS and adds the connection to the reactor as an HTTP/2 connection. All other connections follow the HTTP/1.1 path.
120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 |
# File 'lib/raptor/server.rb', line 120 def accept_connection(listener, reactor) tcp_client = begin listener.is_a?(Binder::SslListener) ? listener.tcp_server.accept_nonblock : listener.accept_nonblock rescue IO::WaitReadable return end if tcp_client.is_a?(TCPSocket) tcp_client.setsockopt(Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1) remote_addr = tcp_client.remote_address.ip_address else remote_addr = "127.0.0.1" end url_scheme = HTTP_SCHEME client = tcp_client if listener.is_a?(Binder::SslListener) url_scheme = HTTPS_SCHEME begin ssl_socket = OpenSSL::SSL::SSLSocket.new(tcp_client, listener.ssl_context) ssl_socket.sync_close = true ssl_socket.accept client = ssl_socket rescue OpenSSL::SSL::SSLError => error warn "SSL handshake failed: #{error.}" tcp_client.close rescue nil return end if ssl_socket.alpn_protocol == H2_PROTOCOL ssl_socket.write(Http2.build_server_settings_frame) rescue nil reactor.add( id: ssl_socket.object_id, socket: ssl_socket, remote_addr: remote_addr, url_scheme: HTTPS_SCHEME, protocol: :http2, writer: Http2::Writer.new ) return end end @request.eager_accept( client, client.object_id, reactor, @thread_pool, remote_addr, url_scheme ) end |
#run ⇒ Thread
Starts the server's main accept loop in a new thread.
The accept loop polls listening sockets for ready connections and accepts them when system capacity allows. It checks reactor backlog before accepting to prevent overload. This provides natural load balancing across multiple worker processes through backpressure control.
73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 |
# File 'lib/raptor/server.rb', line 73 def run Thread.new(@binder.listeners, @reactor, @running) do |server_sockets, reactor, running| Thread.current.name = self.class.name while running.true? begin ready_servers, _, _ = IO.select(server_sockets, nil, nil, 1) rescue IOError, Errno::EBADF break end next unless ready_servers next if @reactor.backlog >= (@thread_pool.size * 1.2).ceil ready_servers.each do |listener| accept_connection(listener, reactor) end end end end |
#shutdown ⇒ void
This method returns an undefined value.
Gracefully shuts down the server.
Stops accepting new connections and closes all listening sockets. The server thread will exit after handling any in-flight accept operations.
102 103 104 105 |
# File 'lib/raptor/server.rb', line 102 def shutdown @running.make_false @binder.close end |