Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

rpc.server

import rpc

Everything here is re-exported by rpc, so import rpc is enough and the names are called as rpc.*. Importing rpc.server on its own works too and reaches the same definitions.

Serving JSON-RPC to many connections at once, over TCP, TLS or a Unix domain socket.

serve() binds a listening socket and spreads the connections it accepts across a pool of worker isolates. Every connection gets an Endpoint of its own, and setup gives it its handlers, so each connection is a full JSON-RPC peer: it answers what its client asks, and it can call its client and notify it in return.

Each worker polls the connections it holds rather than blocking on one, so a quiet client occupies a descriptor and not a thread, and one worker serves many long-lived connections side by side.

Re-exported by rpc.

Functions

serve()

rpc.serve(setup, options: ?dict)

Serves JSON-RPC on a listening socket, across a pool of worker isolates, until it is stopped.

setup is called inside a worker for every connection accepted, with the connection’s own Endpoint and the client’s address, and gives the endpoint its handlers. A worker shares nothing with the others or with this isolate, so setup builds whatever state a connection needs, and is a function of a module, or a function that uses nothing but its own imports.

import rpc

def setup(endpoint, peer) {
  endpoint
    .on_request('add', @(params) => params[0] + params[1])
    .on_request('whoami', @() => peer.to_string())
}

rpc.serve(setup, { port: 4444, framing: 'line' })
OptionMeaningDefault
hostthe address to listen on'127.0.0.1'
portthe port to listen on; 0 picks a free one8000
patha Unix domain socket to listen on, in place of host and portnil
workershow many worker isolates serve connectionsthe number of CPUs
backloghow many accepted connections may wait for a workerworkers * 4
framing'header' for Content-Length headers, 'line' for lines'header'
max_message_sizethe largest message accepted, in bytes64 MiB
max_connections_per_workerthe most connections one worker holds256
idle_timeoutseconds a connection may stay silent before it is closednil, never
read_timeoutseconds a read may wait once a message has begun30
write_timeoutseconds a write may wait30
cert_chain, private_keyPEM strings that put every connection behind TLSnil
on_readycalled here once bound, with the address and a stop functionnil
max_connectionsstop after accepting this many connectionsnil, never

on_ready is called on this isolate once the socket is bound, with the address it is bound to, as a SocketAddr or the socket’s path, and a function that stops the server. Stopping it stops accepting connections; every worker then finishes the message it is handling, closes its connections and ends, and serve() returns. Reaching max_connections stops accepting too, but serves the connections already accepted until each of them closes, and serve() returns after the last.

A connection whose TLS handshake fails, or whose setup raises, is closed and nothing else is affected. A connection that cannot be read is reported to its endpoint’s on_error() handler and closed.

A handler that calls its client with request() holds its worker until the answer arrives, and every other connection on that worker waits with it.

The socket file of a Unix domain socket is removed when the server stops. A file already at path makes binding fail.

A failure accepting connections stops the server as stop would, and raises from serve() once it has.

Parameters

  • setup (function(2)) — Called with each connection’s {Endpoint} and the client’s address.
  • options (?dict) — Default nil, every option at its default.

Raises ValueError when an option holds a value it cannot take.

Raises Error when the socket cannot be bound.


2026, Richard Ore and Zuri contributors