module Ecluse.Proxy (
runProxy,
runServer,
runWorker,
mountBindingFor,
) where
import Data.Map.Strict qualified as Map
import Data.Text qualified as T
import Data.Time (getCurrentTime)
import GHC.Conc (setNumCapabilities)
import Katip (LogEnv, Severity (ErrorS), SimpleLogPayload, katipAddContext, katipAddNamespace, logFM, runKatipContextT, sl)
import Network.HTTP.Client (newManager)
import Network.HTTP.Client.TLS (tlsManagerSettings)
import Network.Wai qualified as Wai
import Network.Wai.Handler.Warp qualified as Warp
import UnliftIO (concurrently_, race_)
import UnliftIO.Async (mapConcurrently_)
import Ecluse.Boot
import Ecluse.Composition (
PublishBudget (PublishBudget, pbBodyBudget, pbMaxRequestBytes),
planMounts,
planPublishTargets,
)
import Ecluse.Composition.BootError (BootError (MemoryPlanOverrideUnsafe), renderBootError)
import Ecluse.Composition.Credential (initCredentialProviders)
import Ecluse.Composition.MemoryPlan (
MemoryPlan (mpAdmissionCapacity, mpDegradations, mpMaxRequestBytes, mpMaxResponseBytes, mpMirrorArtifactTenant, mpOverrideViolations, mpPublishTenant, mpQueueMemoryMaxDepth, mpShedCapabilities),
MirrorArtifactTenant (matMaxBytes),
PublishTenant (ptAggregateBytes),
mirrorArtifactBytesCap,
planCacheConfig,
)
import Ecluse.Composition.MirrorQueue (MirrorRuntimePlan (MirrorWith, NoMirroring), planMirrorRuntime)
import Ecluse.Composition.Plan (resolveMemoryPlanFor)
import Ecluse.Composition.Sizing (connectionPoolSettings)
import Ecluse.Composition.Sizing qualified as Composition
import Ecluse.Composition.Worker (workerPoliciesFor)
import Ecluse.Config (
AppConfig (cfgCache, cfgLimits, cfgRuntime, cfgServer),
LimitsSettings (limMaxNestingDepth, limMaxVersionCount),
RuntimeSettings (rtPrivateConnectionsPerHost, rtPublicConnectionsPerHost),
ServerSettings (srvPort, srvShutdownDrainTimeout),
mountPostureLines,
)
import Ecluse.Core.Credential.Refresh (CredentialError (Unconfigured), CredentialReporters (CredentialReporters, crBreakerReporter, crRefreshReporter))
import Ecluse.Core.Ecosystem (Ecosystem, prefixFor)
import Ecluse.Core.Queue (MirrorQueue, newEnqueueBuffer, noMirrorQueue, reportWorthy)
import Ecluse.Core.Registry.Adapter (
RegistryAdapter,
adapterEcosystem,
adapterFor,
adapterServe,
serveRouter,
)
import Ecluse.Core.Security (Limits (Limits, maxBodyBytes, maxNestingDepth, maxVersionCount))
import Ecluse.Core.Server.Admission (newServeAdmission)
import Ecluse.Core.Server.Admission.Bytes (newByteAdmission)
import Ecluse.Core.Server.Cache (newMetadataCache)
import Ecluse.Core.Server.Context (PackumentDeps, PublishDeps)
import Ecluse.Core.Supervision (
BackoffSchedule (BackoffSchedule, bsBaseMicros, bsCapMicros),
FaultDisposition (Permanent, Transient),
SupervisionPolicy (SupervisionPolicy, spBackoff, spClassify, spLabel),
superviseLoop,
)
import Ecluse.Core.Telemetry.Metrics (BreakerSource (CredentialMint, EffectfulRule), Provider (CodeArtifact))
import Ecluse.Core.Text (displayExceptionT)
import Ecluse.Core.Worker (WorkerPolicies, heartbeatHealthyNow, runWorkerM, workerLoop)
import Ecluse.Proxy.CveSync (CveSyncHandle (csEnv, csReady), cveRuleDepsFor, cveSyncReady, cveSyncScheduleFor, katipFaultReporter, planCveSync)
import Ecluse.Runtime.Cve.Sync (SyncEnv (syncEcosystem), SyncSchedule, runCveSync)
import Ecluse.Runtime.Env (Env, envDdContext, envLogEnv, envMetrics, newWorkerHeartbeat, withEnvWithAdmission, workerRuntimeOf)
import Ecluse.Runtime.Server (MountBinding (..), ServerConfig (scCheckLive, scCheckReady, scDrainTimeout, scOnException, scPort), ShutdownDrainTimeout (ShutdownDrainTimeout), mkServerConfig)
import Ecluse.Runtime.Server qualified as Server
import Ecluse.Runtime.Telemetry.Correlation (ddPayloadNow)
import Ecluse.Runtime.Telemetry.Reporters (
deferredBreakerReporter,
deferredMirrorEnqueueFailure,
deferredRefreshReporter,
installMetrics,
newDeferredMetrics,
)
import Ecluse.Runtime.Telemetry.Tracing (instrumentDataPlaneManagerSettings)
runProxy :: BootEnv -> IO ()
runProxy :: BootEnv -> IO ()
runProxy BootEnv
bootEnv = do
let env :: AppConfig
env = BootEnv -> AppConfig
beConfig BootEnv
bootEnv
let config :: Config
config = BootEnv -> Config
beConfigFull BootEnv
bootEnv
let logEnv :: LogEnv
logEnv = BootEnv -> LogEnv
beLogEnv BootEnv
bootEnv
let telemetry :: Telemetry
telemetry = BootEnv -> Telemetry
beTelemetry BootEnv
bootEnv
deferredMetrics <- IO DeferredMetrics
newDeferredMetrics
let credentialReporters =
CredentialReporters
{ crBreakerReporter :: BreakerReporter
crBreakerReporter = DeferredMetrics -> BreakerSource -> BreakerReporter
deferredBreakerReporter DeferredMetrics
deferredMetrics BreakerSource
CredentialMint
, crRefreshReporter :: RefreshReporter
crRefreshReporter = DeferredMetrics -> Provider -> RefreshReporter
deferredRefreshReporter DeferredMetrics
deferredMetrics Provider
CodeArtifact
}
providers <- initCredentialProviders credentialReporters config >>= orExit (T.unlines . map renderBootError)
cveSyncPlan <- planCveSync logEnv (beAmbient bootEnv) env
let ruleDepsFor = Map Ecosystem CveSyncHandle
-> BreakerReporter -> FaultReporter -> Ecosystem -> RuleDeps
cveRuleDepsFor Map Ecosystem CveSyncHandle
cveSyncPlan (DeferredMetrics -> BreakerSource -> BreakerReporter
deferredBreakerReporter DeferredMetrics
deferredMetrics BreakerSource
EffectfulRule) (LogEnv -> FaultReporter
katipFaultReporter LogEnv
logEnv)
runtimePlan <-
orExit (T.unlines . map renderBootError) (planMirrorRuntime (beAmbient bootEnv) config)
let (plan, planLines) = resolveMemoryPlanFor env (beRuntimePlan bootEnv) runtimePlan
traverse_ (logBootInfo logEnv) planLines
traverse_ (logBootWarning logEnv) (mpDegradations plan)
unless (null (mpOverrideViolations plan)) $
orExit (T.unlines . map renderBootError) (Left [MemoryPlanOverrideUnsafe (mpOverrideViolations plan)])
whenJust (mpShedCapabilities plan) setNumCapabilities
serveAdmission <- newServeAdmission (mpAdmissionCapacity plan)
publishBudget <- forM (mpPublishTenant plan) $ \PublishTenant
tenant -> do
bodyBudget <- Int -> IO ByteAdmission
newByteAdmission (PublishTenant -> Int
ptAggregateBytes PublishTenant
tenant)
pure PublishBudget{pbBodyBudget = bodyBudget, pbMaxRequestBytes = mpMaxRequestBytes plan}
let limits =
Limits
{ maxBodyBytes :: Int
maxBodyBytes = MemoryPlan -> Int
mpMaxResponseBytes MemoryPlan
plan
, maxVersionCount :: Int
maxVersionCount = LimitsSettings -> Int
limMaxVersionCount (AppConfig -> LimitsSettings
cfgLimits AppConfig
env)
, maxNestingDepth :: Int
maxNestingDepth = LimitsSettings -> Int
limMaxNestingDepth (AppConfig -> LimitsSettings
cfgLimits AppConfig
env)
}
bindings <- planMounts mountBindingFor getCurrentTime ruleDepsFor providers limits publishBudget config >>= orExit (T.unlines . map renderBootError)
publishTargets <- orExit (T.unlines . map renderBootError) (planPublishTargets providers config)
fdLimit <- Composition.openFileSoftLimit
let (privateConnections, privateConnectionsLine) = Composition.resolvePrivateConnections (rtPrivateConnectionsPerHost (cfgRuntime env)) fdLimit
logBootInfo logEnv privateConnectionsLine
let (publicConnections, publicConnectionsLine) = Composition.resolvePublicConnections (rtPublicConnectionsPerHost (cfgRuntime env)) fdLimit
logBootInfo logEnv publicConnectionsLine
heartbeat <- newWorkerHeartbeat
let serverConfig =
([MountBinding] -> ServerConfig
mkServerConfig [MountBinding]
bindings)
{ scPort = srvPort (cfgServer env)
, scDrainTimeout = ShutdownDrainTimeout (srvShutdownDrainTimeout (cfgServer env))
, scCheckReady = cveSyncReady cveSyncPlan
,
scCheckLive = case runtimePlan of
MirrorWith MirrorQueuePlan
_ -> WorkerHeartbeat -> IO Bool
heartbeatHealthyNow WorkerHeartbeat
heartbeat
MirrorRuntimePlan
NoMirroring -> Bool -> IO Bool
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Bool
True
, scOnException = warpExceptionHook logEnv
}
logRuleBootOrder logEnv bindings
traverse_ (logBootInfo logEnv) (mountPostureLines config)
(queue, mirrorDrain) <- case runtimePlan of
MirrorWith MirrorQueuePlan
queuePlan -> do
backendQueue <- LogEnv -> Int -> MirrorQueuePlan -> IO MirrorQueue
buildMirrorQueue LogEnv
logEnv (MemoryPlan -> Int
mpQueueMemoryMaxDepth MemoryPlan
plan) MirrorQueuePlan
queuePlan
(q, drainEnqueueBuffer) <-
bufferedMirrorHandOff (logBootWarning logEnv) (deferredMirrorEnqueueFailure deferredMetrics) backendQueue
pure (q, Just drainEnqueueBuffer)
MirrorRuntimePlan
NoMirroring -> do
LogEnv -> Text -> IO ()
logBootInfo LogEnv
logEnv Text
"mirror runtime disabled: no mount mirrors, so no queue is built and no worker starts"
(MirrorQueue, Maybe (IO ())) -> IO (MirrorQueue, Maybe (IO ()))
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (MirrorQueue
noMirrorQueue, Maybe (IO ())
forall a. Maybe a
Nothing)
metadataCache <- newMetadataCache (planCacheConfig (cfgCache env) plan)
publicSettings <- instrumentDataPlaneManagerSettings telemetry tlsManagerSettings
privateSettings <- instrumentDataPlaneManagerSettings telemetry tlsManagerSettings
manager <- newManager (connectionPoolSettings publicConnections publicSettings)
privateManager <- newManager (connectionPoolSettings privateConnections privateSettings)
withEnvWithAdmission serveAdmission queue manager privateManager metadataCache logEnv telemetry heartbeat $ \Env
builtEnv -> do
DeferredMetrics -> Metrics -> IO ()
installMetrics DeferredMetrics
deferredMetrics (Env -> Metrics
envMetrics Env
builtEnv)
let syncTasks :: [IO ()]
syncTasks = Env -> SyncSchedule -> Map Ecosystem CveSyncHandle -> [IO ()]
cveSyncTasks Env
builtEnv (AppConfig -> SyncSchedule
cveSyncScheduleFor AppConfig
env) Map Ecosystem CveSyncHandle
cveSyncPlan
let workerArtifactMaxBytes :: Int
workerArtifactMaxBytes = Int
-> (MirrorArtifactTenant -> Int)
-> Maybe MirrorArtifactTenant
-> Int
forall b a. b -> (a -> b) -> Maybe a -> b
maybe Int
mirrorArtifactBytesCap MirrorArtifactTenant -> Int
matMaxBytes (MemoryPlan -> Maybe MirrorArtifactTenant
mpMirrorArtifactTenant MemoryPlan
plan)
case Maybe (IO ())
mirrorDrain of
Just IO ()
drainEnqueueBuffer ->
IO () -> IO () -> IO ()
forall (m :: * -> *) a b. MonadUnliftIO m => m a -> m b -> m ()
race_
(ServerConfig -> WorkerPolicies -> Env -> IO ()
runServices ServerConfig
serverConfig (Env -> [MountBinding] -> [PublishTarget] -> Int -> WorkerPolicies
workerPoliciesFor Env
builtEnv [MountBinding]
bindings [PublishTarget]
publishTargets Int
workerArtifactMaxBytes) Env
builtEnv)
(IO () -> IO () -> IO ()
forall (m :: * -> *) a b. MonadUnliftIO m => m a -> m b -> m ()
concurrently_ (Env -> IO () -> IO ()
superviseDrain Env
builtEnv IO ()
drainEnqueueBuffer) ((IO () -> IO ()) -> [IO ()] -> IO ()
forall (m :: * -> *) (f :: * -> *) a b.
(MonadUnliftIO m, Foldable f) =>
(a -> m b) -> f a -> m ()
mapConcurrently_ IO () -> IO ()
forall a. a -> a
id [IO ()]
syncTasks))
Maybe (IO ())
Nothing
| [IO ()] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [IO ()]
syncTasks -> ServerConfig -> Env -> IO ()
runServer ServerConfig
serverConfig Env
builtEnv
| Bool
otherwise ->
IO () -> IO () -> IO ()
forall (m :: * -> *) a b. MonadUnliftIO m => m a -> m b -> m ()
race_
(ServerConfig -> Env -> IO ()
runServer ServerConfig
serverConfig Env
builtEnv)
((IO () -> IO ()) -> [IO ()] -> IO ()
forall (m :: * -> *) (f :: * -> *) a b.
(MonadUnliftIO m, Foldable f) =>
(a -> m b) -> f a -> m ()
mapConcurrently_ IO () -> IO ()
forall a. a -> a
id [IO ()]
syncTasks)
bufferedMirrorHandOff :: (Text -> IO ()) -> IO () -> MirrorQueue -> IO (MirrorQueue, IO ())
bufferedMirrorHandOff :: (Text -> IO ()) -> IO () -> MirrorQueue -> IO (MirrorQueue, IO ())
bufferedMirrorHandOff Text -> IO ()
warn IO ()
countEnqueueFailure =
Int
-> (Int -> IO ())
-> (Int -> Text -> IO ())
-> MirrorQueue
-> IO (MirrorQueue, IO ())
newEnqueueBuffer
Int
Composition.mirrorEnqueueBufferDepth
( \Int
drops -> do
Bool -> IO () -> IO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (Int -> Bool
enqueueReportWorthy Int
drops) (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$
Text -> IO ()
warn (Text
"mirror enqueue buffer full: " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Int -> Text
forall b a. (Show a, IsString b) => a -> b
show Int
drops Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
" job(s) dropped so far; each is re-enqueued on the next demand for its artifact")
IO ()
countEnqueueFailure
)
( \Int
failures Text
detail -> do
Bool -> IO () -> IO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (Int -> Bool
enqueueReportWorthy Int
failures) (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$
Text -> IO ()
warn (Text
"mirror enqueue delivery failed (" Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Int -> Text
forall b a. (Show a, IsString b) => a -> b
show Int
failures Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
" so far): " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
detail)
IO ()
countEnqueueFailure
)
enqueueReportWorthy :: Int -> Bool
enqueueReportWorthy :: Int -> Bool
enqueueReportWorthy Int
n = Int -> Int -> Bool
reportWorthy Int
n Int
Composition.mirrorEnqueueReportInterval
cveSyncTasks :: Env -> SyncSchedule -> Map.Map Ecosystem CveSyncHandle -> [IO ()]
cveSyncTasks :: Env -> SyncSchedule -> Map Ecosystem CveSyncHandle -> [IO ()]
cveSyncTasks Env
builtEnv SyncSchedule
schedule Map Ecosystem CveSyncHandle
plan =
[ IO Void -> IO ()
forall (f :: * -> *) a. Functor f => f a -> f ()
void (IO Void -> IO ())
-> (KatipContextT IO Void -> IO Void)
-> KatipContextT IO Void
-> IO ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. LogEnv
-> SimpleLogPayload
-> Namespace
-> KatipContextT IO Void
-> IO Void
forall c (m :: * -> *) a.
LogItem c =>
LogEnv -> c -> Namespace -> KatipContextT m a -> m a
runKatipContextT (Env -> LogEnv
envLogEnv Env
builtEnv) (SimpleLogPayload
forall a. Monoid a => a
mempty :: SimpleLogPayload) Namespace
"cve-sync" (KatipContextT IO Void -> IO ()) -> KatipContextT IO Void -> IO ()
forall a b. (a -> b) -> a -> b
$
SupervisionPolicy -> KatipContextT IO () -> KatipContextT IO Void
forall (m :: * -> *).
(MonadUnliftIO m, KatipContext m) =>
SupervisionPolicy -> m () -> m Void
superviseLoop
(Text -> SupervisionPolicy
transientPolicy (Text
"cve-sync[" Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Ecosystem -> Text
forall b a. (Show a, IsString b) => a -> b
show (SyncEnv -> Ecosystem
syncEcosystem (CveSyncHandle -> SyncEnv
csEnv CveSyncHandle
handle)) Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"]"))
(SyncEnv -> SyncSchedule -> IO () -> KatipContextT IO ()
forall (m :: * -> *).
(MonadUnliftIO m, KatipContext m) =>
SyncEnv -> SyncSchedule -> IO () -> m ()
runCveSync (CveSyncHandle -> SyncEnv
csEnv CveSyncHandle
handle) SyncSchedule
schedule (STM () -> IO ()
forall (m :: * -> *) a. MonadIO m => STM a -> m a
atomically (TVar Bool -> Bool -> STM ()
forall a. TVar a -> a -> STM ()
writeTVar (CveSyncHandle -> TVar Bool
csReady CveSyncHandle
handle) Bool
True)))
| CveSyncHandle
handle <- Map Ecosystem CveSyncHandle -> [CveSyncHandle]
forall k a. Map k a -> [a]
Map.elems Map Ecosystem CveSyncHandle
plan
]
transientPolicy :: Text -> SupervisionPolicy
transientPolicy :: Text -> SupervisionPolicy
transientPolicy Text
label =
SupervisionPolicy
{ spLabel :: Text
spLabel = Text
label
, spClassify :: SomeException -> FaultDisposition
spClassify = FaultDisposition -> SomeException -> FaultDisposition
forall a b. a -> b -> a
const FaultDisposition
Transient
, spBackoff :: BackoffSchedule
spBackoff = BackoffSchedule{bsBaseMicros :: Int
bsBaseMicros = Int
1_000_000, bsCapMicros :: Int
bsCapMicros = Int
30_000_000}
}
superviseDrain :: Env -> IO () -> IO ()
superviseDrain :: Env -> IO () -> IO ()
superviseDrain Env
builtEnv IO ()
drain =
IO Void -> IO ()
forall (f :: * -> *) a. Functor f => f a -> f ()
void (IO Void -> IO ())
-> (KatipContextT IO Void -> IO Void)
-> KatipContextT IO Void
-> IO ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. LogEnv
-> SimpleLogPayload
-> Namespace
-> KatipContextT IO Void
-> IO Void
forall c (m :: * -> *) a.
LogItem c =>
LogEnv -> c -> Namespace -> KatipContextT m a -> m a
runKatipContextT (Env -> LogEnv
envLogEnv Env
builtEnv) (SimpleLogPayload
forall a. Monoid a => a
mempty :: SimpleLogPayload) Namespace
"mirror-enqueue-drain" (KatipContextT IO Void -> IO ()) -> KatipContextT IO Void -> IO ()
forall a b. (a -> b) -> a -> b
$
SupervisionPolicy -> KatipContextT IO () -> KatipContextT IO Void
forall (m :: * -> *).
(MonadUnliftIO m, KatipContext m) =>
SupervisionPolicy -> m () -> m Void
superviseLoop (Text -> SupervisionPolicy
transientPolicy Text
"mirror-enqueue-drain") (IO () -> KatipContextT IO ()
forall a. IO a -> KatipContextT IO a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO IO ()
drain)
runServices :: ServerConfig -> WorkerPolicies -> Env -> IO ()
runServices :: ServerConfig -> WorkerPolicies -> Env -> IO ()
runServices ServerConfig
serverConfig WorkerPolicies
policies Env
env =
IO () -> IO () -> IO ()
forall (m :: * -> *). MonadUnliftIO m => m () -> m () -> m ()
Server.raceServerAgainstLoop (ServerConfig -> Env -> IO ()
runServer ServerConfig
serverConfig Env
env) (WorkerPolicies -> Env -> IO ()
runWorker WorkerPolicies
policies Env
env)
runServer :: ServerConfig -> Env -> IO ()
runServer :: ServerConfig -> Env -> IO ()
runServer ServerConfig
cfg Env
env = ServerConfig -> (ServerConfig -> IO Application) -> IO ()
Server.runWarp ServerConfig
cfg (ServerConfig -> Env -> IO Application
`Server.tracedApplication` Env
env)
warpExceptionHook :: LogEnv -> Maybe Wai.Request -> SomeException -> IO ()
warpExceptionHook :: LogEnv -> Maybe Request -> SomeException -> IO ()
warpExceptionHook LogEnv
logEnv Maybe Request
mRequest SomeException
err =
Bool -> IO () -> IO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (SomeException -> Bool
Warp.defaultShouldDisplayException SomeException
err) (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$
LogEnv
-> SimpleLogPayload -> Namespace -> KatipContextT IO () -> IO ()
forall c (m :: * -> *) a.
LogItem c =>
LogEnv -> c -> Namespace -> KatipContextT m a -> m a
runKatipContextT LogEnv
logEnv (SimpleLogPayload
forall a. Monoid a => a
mempty :: SimpleLogPayload) Namespace
"server" (KatipContextT IO () -> IO ()) -> KatipContextT IO () -> IO ()
forall a b. (a -> b) -> a -> b
$
SimpleLogPayload -> KatipContextT IO () -> KatipContextT IO ()
forall i (m :: * -> *) a.
(LogItem i, KatipContext m) =>
i -> m a -> m a
katipAddContext SimpleLogPayload
payload (KatipContextT IO () -> KatipContextT IO ())
-> KatipContextT IO () -> KatipContextT IO ()
forall a b. (a -> b) -> a -> b
$
Severity -> LogStr -> KatipContextT IO ()
forall (m :: * -> *).
(Applicative m, KatipContext m) =>
Severity -> LogStr -> m ()
logFM Severity
ErrorS LogStr
"a fault escaped to the server (a post-commit teardown, or warp's own connection handling)"
where
payload :: SimpleLogPayload
payload =
Text -> Text -> SimpleLogPayload
forall a. ToJSON a => Text -> a -> SimpleLogPayload
sl Text
"path" (Text -> (Request -> Text) -> Maybe Request -> Text
forall b a. b -> (a -> b) -> Maybe a -> b
maybe (Text
"unknown" :: Text) (ByteString -> Text
forall a b. ConvertUtf8 a b => b -> a
decodeUtf8 (ByteString -> Text) -> (Request -> ByteString) -> Request -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Request -> ByteString
Wai.rawPathInfo) Maybe Request
mRequest)
SimpleLogPayload -> SimpleLogPayload -> SimpleLogPayload
forall a. Semigroup a => a -> a -> a
<> Text -> Text -> SimpleLogPayload
forall a. ToJSON a => Text -> a -> SimpleLogPayload
sl Text
"detail" (SomeException -> Text
forall e. Exception e => e -> Text
displayExceptionT SomeException
err)
mountBindingFor :: Ecosystem -> PackumentDeps -> Maybe PublishDeps -> Maybe MountBinding
mountBindingFor :: Ecosystem
-> PackumentDeps -> Maybe PublishDeps -> Maybe MountBinding
mountBindingFor Ecosystem
eco PackumentDeps
packumentDeps Maybe PublishDeps
publishDeps =
Ecosystem -> Maybe RegistryAdapter
adapterFor Ecosystem
eco Maybe RegistryAdapter
-> (RegistryAdapter -> MountBinding) -> Maybe MountBinding
forall (f :: * -> *) a b. Functor f => f a -> (a -> b) -> f b
<&> \RegistryAdapter
adapter -> RegistryAdapter
-> PackumentDeps -> Maybe PublishDeps -> MountBinding
mountOf RegistryAdapter
adapter PackumentDeps
packumentDeps Maybe PublishDeps
publishDeps
mountOf :: RegistryAdapter -> PackumentDeps -> Maybe PublishDeps -> MountBinding
mountOf :: RegistryAdapter
-> PackumentDeps -> Maybe PublishDeps -> MountBinding
mountOf RegistryAdapter
adapter PackumentDeps
packumentDeps Maybe PublishDeps
publishDeps =
MountBinding
{ bindingPrefix :: NonEmpty Text
bindingPrefix = Ecosystem -> NonEmpty Text
prefixFor (RegistryAdapter -> Ecosystem
adapterEcosystem RegistryAdapter
adapter)
, bindingRouter :: MountRouter
bindingRouter = AdapterServe -> MountRouter
serveRouter (RegistryAdapter -> AdapterServe
adapterServe RegistryAdapter
adapter)
, bindingPackumentDeps :: PackumentDeps
bindingPackumentDeps = PackumentDeps
packumentDeps
, bindingPublishDeps :: Maybe PublishDeps
bindingPublishDeps = Maybe PublishDeps
publishDeps
}
runWorker :: WorkerPolicies -> Env -> IO ()
runWorker :: WorkerPolicies -> Env -> IO ()
runWorker WorkerPolicies
policies Env
env = do
dd <- DdContext -> IO SimpleLogPayload
forall (m :: * -> *). MonadIO m => DdContext -> m SimpleLogPayload
ddPayloadNow (Env -> DdContext
envDdContext Env
env)
void (runWorkerM (envLogEnv env) dd (workerRuntimeOf policies env) (katipAddNamespace "worker" (workerLoop workerSupervision)))
workerSupervision :: SupervisionPolicy
workerSupervision :: SupervisionPolicy
workerSupervision =
SupervisionPolicy
{ spLabel :: Text
spLabel = Text
"worker"
, spClassify :: SomeException -> FaultDisposition
spClassify = SomeException -> FaultDisposition
classify
, spBackoff :: BackoffSchedule
spBackoff = BackoffSchedule{bsBaseMicros :: Int
bsBaseMicros = Int
1_000_000, bsCapMicros :: Int
bsCapMicros = Int
30_000_000}
}
where
classify :: SomeException -> FaultDisposition
classify SomeException
fault
| Just (Unconfigured Text
_) <- SomeException -> Maybe CredentialError
forall e. Exception e => SomeException -> Maybe e
fromException SomeException
fault = FaultDisposition
Permanent
| Bool
otherwise = FaultDisposition
Transient