| Safe Haskell | None |
|---|---|
| Language | GHC2021 |
Ecluse.Runtime.Server.Internal
Description
The dispatch, the request perimeter and the listener behind Ecluse.Runtime.Server, which
documents the front door and re-exports the curated surface. Importing this module opts out of
that stability promise, the convention text and bytestring use, so production code imports
the public one.
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
- defaultPort :: Int
- 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 ()
- serveBound :: LogEnv -> Text -> Settings -> Application -> IO ()
- proxyListener :: Text
- listeningPrefix :: Text -> Text
- raceServerAgainstLoop :: MonadUnliftIO m => m () -> m () -> m ()
- probeApplication :: DrainSignal -> IO Readiness -> IO Liveness -> Application
- probeOnlyApplication :: ServerConfig -> IO Application
- perimeterGuard :: (RequestFault -> IO ()) -> (response -> IO ResponseReceived) -> response -> ((response -> IO ResponseReceived) -> IO ResponseReceived) -> IO ResponseReceived
- 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.
defaultPort :: Int Source #
The conventional npm proxy listen port (4873), the mkServerConfig default.
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.
serveBound :: LogEnv -> Text -> Settings -> Application -> IO () Source #
Bind as runSettings does, log the bound port, then serve.
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.
The typed request perimeter
Arguments
| :: (RequestFault -> IO ()) | Observe a classified pre-commit fault (the metric and the audit line). |
| -> (response -> IO ResponseReceived) | The route-scoped response continuation. |
| -> response | The route's declared neutral pre-commit fallback. |
| -> ((response -> IO ResponseReceived) -> IO ResponseReceived) | The route's handler, discharged to |
| -> IO ResponseReceived |
Run one route's handler behind a commit-tracking respond, catching synchronous escapes only. Pre-commit one answers the neutral fallback with no detail, post-commit it rethrows.
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.