Repository navigation
feat(#184): laurel.serve, a standalone host with built-in providers - #188
Merged
Merged
Conversation
laurel.testing.tasks becomes laurel.task.runner, the runner both hosts use. Every provider call and poll take the runner's lock and a step runs with it released, so a step can publish or trigger through the provider and handlers can read snapshots from any thread. on_wake tells a driver of new work, and next_due and busy say when to poll again. laurel.testing still drives it by hand with a fixed clock.
laurel.serve needs http 0.23's server runner, its settle call and wake_at, and its framing of unframed responses. The hedge-hosted demo and bench server override hedge 0.12.0's =0.21.0 pin by ref until they move to graft, since 0.22 and 0.23 only add the runner and fix the h1 engine compatibly.
serve.Host owns the built-in providers (the task runner on its own thread, configuration and secrets from the environment, telemetry on stderr), handed to the application as one provider entry it can override key by key. serve.run serves the application on http.server.server: each exchange is routed, bound, executed and resumed through app, woken at its handler deadline through wake_at, and released when the server settles it. The lifecycle runs through the server's start, ready, drain and stop hooks, the task provider drains beside it, and SIGTERM or SIGINT begins the bounded drain. Tests: the same assemble under laurel.testing, and a real socket served, signalled with SIGTERM while a request is in flight, and drained.
demo/standalone is one application written against its host's providers: a text route, a configuration value, a periodic task's snapshot and telemetry, and a body echo that suspends on the host. bin/main.mach hosts it with laurel.serve, and its test runs the same assemble in process under laurel.testing. CI builds it and runs the test on the primary leg.
doc/serve.md states the laurel.serve contract: running, the lifecycle mapping, signals and drain, request handling, and the current limits, no WebSockets until mach-http#191 and long streams bounded by the runner's whole-exchange deadline until mach-http#193. doc/providers.md describes the shared task runner and the built-in providers, and the README shows both hosting modes.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #184
The serve half of #184, on top of the provider interfaces from #185. Part of #183.
Plan
laurel.serve:serve.Hostis created first and owns the built-in providers, whichserve.providers(host)hands the application as oneprovider.Providerentry.serve.run(host, app, config)serves an assembled application onhttp.server.serveruntil a drain finishes, thenserve.destroy(host).serveroutes, binds (app.bind_context), executes, and resumes a suspended step when the server re-enters it. A step's handler deadline is handed to the server asCall.wake_at, and a step past it is timed out through the exchange scope.abandonruns the owed middleware exit halves, and the server'ssettlereleases the context (app.release_context) once the response is written, so the terminal event carries the final transfer and a drain waits for responses still on the wire. A request the application cannot admit is answered 503.app.start, ready isapp.poll_readythenConfig.ready, drain(deadline) isapp.drainplustask.drainon the application's task provider with the same deadline, and stop isapp.stopthentask.stop. A start the server abandons never reaches its stop hook, sorunstops the application and tasks itself withinstop_timeout_ns.Config.signals,runowns the process'sstd.process.eventssource for its duration, and SIGTERM or SIGINT (console close or service stop on windows) callshs.shutdown, the bounded drain todrain_timeout_ns.laurel.testing.tasksbecomeslaurel.task.runner, one runner for both hosts. It is now thread-safe: every call andpolltake its lock, and a step runs with it released.laurel.testingsteps it by hand, andlaurel.servedrives it from its own thread, woken byon_wakeandnext_due.demo/standaloneis one application, hosted bylaurel.serveinbin/main.machand tested in process underlaurel.testingwith the sameassemble. CI builds it and runs its test on the primary leg.doc/serve.md(the contract and the current limits),doc/providers.md(runner and built-ins), and the README's two hosting modes.^0.23at v0.23.0 viamach dep update.Needed from mach-http, released as 0.22.0 and 0.23.0
Handler.settle, since nothing told a handler when its exchange was terminal, andCall.wake_at, so a handler deadline needs no timer thread.Current limits, stated in doc/serve.md and the README
Not in this PR
The hedge-hosted demo, and the bench server hosted the same way, stay here until graft takes them (briar-systems/graft#1). hedge 0.12.0 pins http
=0.21.0, so both override it byref = "tag/v0.23.0". 0.22 and 0.23 only add the runner and fix the h1 engine compatibly, and the demo builds that way.Local runs
mach 6.3.0:
mach test .for the library,mach test demo/standalone, andmach build demo. I ran the example binary with curl (keep-alive, framing, config, task snapshot, echo) and sent it SIGTERM. The SIGTERM test also ran against a counterfactual with the signal thread's shutdown removed, and it fails.