| Safe Haskell | None |
|---|---|
| Language | GHC2021 |
Ecluse.Runtime.Server
Description
The HTTP front door: the raw wai Application, its dispatch, the middleware stack, and
runWarp. It is a raw Application rather than a framework because matching on pathInfo
keeps the encoded-slash handling and the streaming control the proxy depends on
(docs/architecture/web-layer.md). Dispatch matches a request's leading segments to a
configured MountBinding, strips the prefix, and asks that mount's router what the remainder
names, so this module holds no path grammar and no status of its own. A path under no mount is
the neutral 404, and /livez and /readyz are answered above the mounts.
Synopsis
- data ServerConfig = ServerConfig {
- scPort :: Int
- scMounts :: [MountBinding]
- scDrain :: DrainSignal
- scDrainTimeout :: ShutdownDrainTimeout
- scCheckReady :: IO Readiness
- scCheckLive :: IO Liveness
- scOnException :: Maybe Request -> SomeException -> IO ()
- mkServerConfig :: [MountBinding] -> ServerConfig
- data MountBinding = MountBinding {
- bindingPrefix :: NonEmpty Text
- bindingRouter :: MountRouter
- bindingCredential :: CredentialMapping
- bindingPackumentDeps :: PackumentDeps
- bindingPublishDeps :: Maybe PublishDeps
- application :: ServerConfig -> Env -> Application
- tracedApplication :: ServerConfig -> Env -> IO Application
- runWarp :: LogEnv -> Text -> ServerConfig -> (ServerConfig -> IO Application) -> IO ()
- proxyListener :: Text
- listeningPrefix :: Text -> Text
- raceServerAgainstLoop :: MonadUnliftIO m => m () -> m () -> m ()
- probeApplication :: DrainSignal -> IO Readiness -> IO Liveness -> Application
- probeOnlyApplication :: ServerConfig -> IO Application
- data DrainSignal
- newDrainSignal :: IO DrainSignal
- neverDraining :: DrainSignal
- beginDrain :: DrainSignal -> IO ()
- isDraining :: DrainSignal -> IO Bool
- newtype ShutdownDrainTimeout = ShutdownDrainTimeout Int
- defaultShutdownDrainTimeout :: ShutdownDrainTimeout
- data InteractiveHalt = InteractiveHalt {
- haltOnInteractive :: IO Bool
- awaitHaltSignal :: IO ()
- halt :: IO ()
- defaultInteractiveHalt :: InteractiveHalt
- withInteractiveHalt :: InteractiveHalt -> IO a -> IO a
- serverMiddleware :: ServerConfig -> Middleware
The WAI application
data ServerConfig Source #
The settings the web layer needs to serve that the composition-root Env does not carry.
Not the request-body cap: the publish route bounds its own body as a value.
Constructors
| ServerConfig | |
Fields
| |
mkServerConfig :: [MountBinding] -> ServerConfig Source #
Build a ServerConfig over the mount bindings on defaultPort. There is no built-in
mount: the web layer serves only the ecosystems the composition root binds here.
data MountBinding #
Constructors
| MountBinding | |
Fields
| |
application :: ServerConfig -> Env -> Application Source #
The proxy's WAI Application: the request dispatch under the cross-cutting
middleware stack (serverMiddleware).
tracedApplication :: ServerConfig -> Env -> IO Application Source #
application with the OpenTelemetry server-span middleware wrapped outermost, so
one server span covers the whole request. The wrapper is id when telemetry is off.
Running the server
runWarp :: LogEnv -> Text -> ServerConfig -> (ServerConfig -> IO Application) -> IO () Source #
Serve the front door over one live DrainSignal, which the probe, the going-away header,
and the shutdown handler share. warp drains under scDrainTimeout, and a TTY adds Ctrl-D.
proxyListener :: Text Source #
The proxy's listener name, which starts the line it logs once bound.
listeningPrefix :: Text -> Text Source #
The start of the line a named listener logs once bound, followed by the port.
raceServerAgainstLoop :: MonadUnliftIO m => m () -> m () -> m () Source #
Race a server arm against a never-returning background loop, the single-process shutdown
shape. race_ is the invariant: concurrently_ would wait forever, brackets un-unwound.
probeApplication :: DrainSignal -> IO Readiness -> IO Liveness -> Application Source #
The control-plane health probes, answered above any mount: /livez from the injected
liveness check, /readyz from the drain signal and startup gate. Any other path is a 404.
probeOnlyApplication :: ServerConfig -> IO Application Source #
The WAI Application of a role that serves the health probes and nothing else. Every
path outside /livez and /readyz is the neutral 404.
Graceful shutdown
data DrainSignal Source #
The shutdown-drain flag the front door observes during a graceful rollover. Nothing lowers it again. The readiness probe and the going-away middleware read it per request.
newDrainSignal :: IO DrainSignal Source #
Allocate a live drain signal, lowered. runWarp allocates one per launch and raises
it from the shutdown signal handler.
neverDraining :: DrainSignal Source #
The inert drain signal: permanently lowered, and raising it does nothing. It is the
mkServerConfig default, so a socket-free test reports ready and stamps no going-away header.
beginDrain :: DrainSignal -> IO () Source #
Raise a drain signal: the one-way transition into draining. Idempotent.
isDraining :: DrainSignal -> IO Bool Source #
Read whether a drain signal is raised.
newtype ShutdownDrainTimeout Source #
The bound on the graceful drain, in seconds. The server stops accepting connections, waits this long for in-flight requests and artifact streams, then exits regardless.
Constructors
| ShutdownDrainTimeout Int |
Instances
| Show ShutdownDrainTimeout Source # | |
Defined in Ecluse.Runtime.Server.Drain Methods showsPrec :: Int -> ShutdownDrainTimeout -> ShowS # show :: ShutdownDrainTimeout -> String # showList :: [ShutdownDrainTimeout] -> ShowS # | |
| Eq ShutdownDrainTimeout Source # | |
Defined in Ecluse.Runtime.Server.Drain Methods (==) :: ShutdownDrainTimeout -> ShutdownDrainTimeout -> Bool # (/=) :: ShutdownDrainTimeout -> ShutdownDrainTimeout -> Bool # | |
defaultShutdownDrainTimeout :: ShutdownDrainTimeout Source #
The default graceful-drain bound: 30 seconds. It covers an in-flight metadata fetch or a moderate artifact stream, and stops a stuck request pinning the old instance.
Local-dev immediate halt
data InteractiveHalt Source #
The local-development immediate-halt wiring, as injection points a test drives without a terminal. Ctrl-D exits the process at once and aborts the drain. It is inert on a non-TTY.
Constructors
| InteractiveHalt | |
Fields
| |
defaultInteractiveHalt :: InteractiveHalt Source #
The real local-dev halt: armed only on a terminal and fired by end-of-input, exiting at once without a drain. Status 130 is the conventional "terminated from the terminal" code.
withInteractiveHalt :: InteractiveHalt -> IO a -> IO a Source #
Run an action with the immediate-halt watcher armed only when haltOnInteractive is
True. The watcher lives exactly as long as the action, so it never outlives it.
Middleware
serverMiddleware :: ServerConfig -> Middleware Source #
The cross-cutting stack around the proxy Application. The body cap is not a middleware:
it would throw across the request perimeter, and Autohead and Gzip fight streaming.