Async Handler Proxy
A Node http.createServer async handler that awaits a *task-shaped* promise while serving a request — a proxy front. The handler awaits proxyGet, a may-suspend async fn that itself awaits fetch; awaiting its result on the connection fiber is a task-promise await (distinct from awaiting fetch directly). Before the fix, that combination corrupted the event loop's main context and crashed the server on the first request.
Self-contained on the single event loop, like examples/http/client_server.ts: the front proxies to a local fixture (tools/httpbin-lite/, started by `make examples` — see), and an in-process client drives it. Runs unchanged under Node.js (pointed at any upstream).
import http from 'http'
// A may-suspend async fn: it awaits fetch, so a caller that awaits *it* parks
// on a task-shaped promise rather than on the fetch transfer directly.
async function proxyGet(path: string): Promise<string> {
const r = await fetch('http://127.0.0.1:8765' + path)
return await r.text()
}
const server = http.createServer(async (req: http.IncomingMessage, res: http.ServerResponse) => {
const upstream = await proxyGet('/get')
res.writeHead(200, { "Content-Type": "text/plain" })
res.end("proxied " + upstream.length + " bytes")
console.log("front served a proxied response of", upstream.length, "bytes")
// The server never returns on its own; exit shortly after serving the one
// request (this example harness only — a real server omits this).
setTimeout(() => { process.exit(0) }, 50)
})
server.listen(18536, () => {
// Drive the front from the same process, on the same event loop.
http.get("http://127.0.0.1:18536/", (res) => {
res.on('data', (_chunk: string) => {})
res.on('end', () => {})
})
})View source on GitHubexamples/http/async_handler_proxy.ts