{"name":"async_http_server.nu","source":"// examples/async_http_server.nu — fiber-driven HTTP server demo.\n//\n// Same handler contract as `examples/static_server.nu`, but runs the\n// accept loop and every per-connection keep-alive loop on stackful\n// fibers via the Phase 7 async runtime. Each accepted connection\n// becomes a fiber; the M:N work-stealing scheduler distributes them\n// across N worker pthreads (default = sysconf(_SC_NPROCESSORS_ONLN),\n// override with NURL_WORKERS env). Slow handlers no longer pin a\n// worker — `tcp_read_chunk` and `tcp_write_all` park the fiber on\n// the reactor when the kernel returns EAGAIN, and a different\n// fiber's work runs in the meantime.\n//\n// Build:\n//   ./nurl.sh examples/async_http_server.nu\n//\n// Test:\n//   curl -i http://localhost:8082/\n//   curl -i http://localhost:8082/api/health\n//   ab -c 100 -n 10000 http://localhost:8082/api/health    # benchmark\n//\n// Shutdown: send SIGINT (Ctrl+C) or SIGTERM — the signal handler\n// closes the listener; the accept fiber exits; `runtime_run` drains\n// every in-flight connection fiber; `runtime_shutdown` joins the\n// worker pool cleanly. No connection is dropped mid-flight.\n\n$ `stdlib/std/async.nu`\n$ `stdlib/ext/http_full.nu`\n\n@ health_handler HttpRequest req Params params → HttpResponse {\n    ^ ( response_text 200 `{\"status\":\"ok\"}\\n` )\n}\n\n@ root_handler HttpRequest req Params params → HttpResponse {\n    ^ ( response_text 200 `nurl async server — stackful fibers + M:N work-stealing\\n` )\n}\n\n@ main → i {\n    // 1. Initialise the async runtime. 0 = pick a sensible default\n    //    worker count from NURL_WORKERS / sysconf.\n    ( runtime_init 0 )\n\n    // 2. Bind a listener on loopback:8082.\n    : !TcpListener NetErr lr ( tcp_listen `127.0.0.1` 8082 )\n    ?? lr {\n        T listener → {\n            // 3. Router — two routes, both wrapped as closure literals\n            //    (bare `@`-fn names don't auto-coerce to `( @ R P P )`).\n            : Router r ( router_new )\n            ( router_get r `/`\n            \\ HttpRequest req Params params → HttpResponse { ^ ( root_handler req params ) } )\n            ( router_get r `/api/health`\n            \\ HttpRequest req Params params → HttpResponse { ^ ( health_handler req params ) } )\n\n            // Middleware compose, innermost-first — same shape as the\n            // sync `examples/static_server.nu`.\n            : Metrics mtr ( metrics_new )\n            : ( @ HttpResponse HttpRequest ) base\n            \\ HttpRequest req → HttpResponse { ^ ( router_handle r req ) }\n            : ( @ HttpResponse HttpRequest ) metered ( with_metrics mtr base )\n            : ( @ HttpResponse HttpRequest ) logged ( with_access_log metered )\n\n            : HttpServer srv ( server_new listener logged )\n\n            // 4. SIGINT/SIGTERM/Ctrl+C: close the listener, which\n            //    makes the accept fiber exit naturally.\n            ( signal_install_shutdown listener )\n\n            ( nurl_print `nurl async HTTP server listening on http://127.0.0.1:8082/\\n` )\n            ( nurl_print `  routes: / and /api/health\\n` )\n            ( nurl_print `  workers: ` )\n            ( nurl_print ( nurl_str_int ( nurl_fiber_worker_id ) ) )\n            ( nurl_print ` (id from main; -1 = not on a fiber)\\n` )\n\n            // 5. Hand off to the async runtime. Returns when the\n            //    accept loop exits AND every conn fiber drains.\n            : !v NetErr rr ( server_run_async srv )\n            ?? rr {\n                T _ → { ( nurl_print `server exited cleanly\\n` ) }\n                F e → {\n                    ( nurl_print `server exit: ` )\n                    ( nurl_print ( net_err_name e ) )\n                    ( nurl_print `\\n` )\n                }\n            }\n\n            ( runtime_shutdown )\n            ( tcp_close_listener listener )\n            ( metrics_free mtr )\n            ( router_free r )\n        }\n        F e → {\n            ( nurl_print `bind failed: ` )\n            ( nurl_print ( net_err_name e ) )\n            ( nurl_print `\\n` )\n            ^ 1\n        }\n    }\n    ^ 0\n}\n","bytes":4046}