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

http.worker

import http

http exposes this as http.worker, so import http is enough and the names are called as http.worker.*. import http.worker reaches the same definitions directly.

The multi-process side of HttpServer: a pool of isolates, each accepting and serving connections from the same listening socket.

Each worker polls the connections it holds rather than blocking on one, so a slow client occupies a descriptor and not a thread. This is what HttpServer uses when it is configured with more than one worker.

Functions

worker_main()

http.worker.worker_main(connections, setup, options)

The loop each worker isolate runs: build a server of its own from setup, then serve whatever connections the acceptor hands it.

This lives in a module because it names imported ones of its own (HttpServer, net). A module value cannot be handed to an isolate, but a function belonging to a module is resolved there by name, with its imports resolved again on that side.

Parameters

  • connections (Channel) — accepted sockets arrive here
  • setup (function(1)) — called once with this worker’s server
  • options (dict)

serve()

http.worker.serve(setup, options: ?dict)

Binds a listening socket and serves it across a pool of worker isolates.

The calling isolate does nothing but accept, which is cheap; every accepted socket is moved across a channel to whichever worker takes it next. Because isolates share no memory, each worker builds its own routes by calling setup.

backlog is how many accepted-but-unclaimed connections may queue before the acceptor blocks. Bounding it is deliberate: an unbounded queue under load means accepting connections faster than they can be served and answering all of them late, rather than letting the kernel’s own listen backlog apply back-pressure.

on_ready is called once in this isolate with the bound address and a function that stops the server, which is what a signal handler needs in order to shut down cleanly:

http.serve(app.setup, {
  port: 3000,
  on_ready: @(address, stop) {
    echo 'listening on ${address}'
    os.on_signal('INT', @() {
      stop()
      return true
    })
  },
})

Parameters

  • setup (function(1))
  • options (?dict) — port, host, workers, backlog, on_ready, max_connections (stop after serving that many), cert_chain, private_key, plus any HttpServer field to apply to every worker

Raises HttpError if the socket cannot be bound

Note: Each worker holds an isolate pool thread for as long as the server runs. serve() sizes the pool for that when it is the first thing in the process to use an isolate; when it is not - because something already spawned one, fixing the pool’s size - it raises rather than deadlocking behind workers that never finish. Call isolate.configure() yourself, first thing, if the process needs isolates for anything besides serving.


2026, Richard Ore and Zuri contributors