← index

[Web]Pool

inherits Object · defined at web/05-pool.qn:25

Multi-core request execution over worker isolates — the pool behind [Web]App's serve:workers: (docs/internal/WEB_ARCH.md workers; docs/internal/CONCURRENCY_ARCH.md §13).

Sockets never cross worker lanes — the transport VM keeps every connection, and REQUESTS TRAVEL AS DATA: a connection task ships #{id method target headers body} to a pool worker, the worker runs the whole pure pipeline (app.handle:), and replies #{id status headers body}. [Web]App.handle:'s no-sockets purity is exactly what makes it shippable.

Provisioning is the same-unit model: each pool worker re-runs the app's OWN unit (VM.unit), whose serve:workers: call detects the worker context and enters the request loop instead of binding a listener. The pool pre-buffers a 'webpool-init' sentinel at spawn (the lanes exist before the worker boots), so the worker-side loop can VERIFY it was spawned by a pool rather than guessing from context.

One reply-router task per worker demultiplexes correlation ids into per-request channels; dispatch is round-robin, skipping dead workers. A worker death fails ITS in-flight requests with 502 (per-worker pending maps — a crash never spuriously fails a sibling's requests). Streaming (Generator) response bodies MATERIALIZE in pool mode (chunked streaming over the lanes is a recorded follow-up).

Class methods

dataToRequest:

Data -> request, worker side. Content type/encoding ride the header list; the body arrives bytes-backed, so .json/.form work in the worker exactly as they would have in the main VM.

web/05-pool.qn:53

dataToResponse:

Wire data -> [HTTP]ServerResponse, transport side (plain single-frame replies; streamed replies rebuild in handle: instead).

web/05-pool.qn:98

reply: id:

Response -> frames, worker side (called from the request's own Task, so a stream's frames leave in order). A plain body is ONE terminal frame; a Generator body STREAMS: a head frame (stream: true), one chunk frame per yield, a terminal end frame. A mid-stream generator error truncates (the chunked wire has no mid-body error signal) — the end frame closes the correlation either way.

web/05-pool.qn:73

requestToData: id:

Request -> wire data, transport side: headers stay the order/duplicate-preserving #(name value) pair list; the body drains to bytes here in the transport VM (it is stream-backed until someone reads it).

web/05-pool.qn:39

spawn: unit: backing:

Spawn a pool of n workers, each re-running unit under a 'thread' or 'process' backing, and return it ready to handle:.

web/05-pool.qn:29

Instance methods

aliveCount

How many pool workers are still alive.

web/05-pool.qn:176

handle:

Ship one request, park the calling (connection) task on its reply channel, rebuild the response. Round-robin over live workers; a send to a just-died worker marks it and retries the next; all dead -> 503.

web/05-pool.qn:185

init

Internal: empty registries — workers, liveness, per-worker pendings, routers.

web/05-pool.qn:108

markDead:

Internal: mark worker i dead and fail its in-flight requests with a 502.

web/05-pool.qn:165

startWorkers: unit: backing:

Internal: spawn the n workers (pool sentinel pre-buffered) and one reply-router task per worker; returns self.

web/05-pool.qn:119

stop

Drain-not-graceful: stop every worker's loop and join it; in-flight handler tasks in that worker end with it.

web/05-pool.qn:245