server: refactor serverctx data types

## Description
This PR merges the data type `ServeCtx` into `ServerCtx` to create a single data type which has all the required context to run HGE.

## Motivation
This consolidated data type will be easier to update/maintain in case of any changes to the user config.

### Related Issues
https://hasurahq.atlassian.net/browse/GS-301

[GS-301]: https://hasurahq.atlassian.net/browse/GS-301?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ

PR-URL: https://github.com/hasura/graphql-engine-mono/pull/7396
GitOrigin-RevId: f37594d15855bb50e556a4b11a58609af3f9f312
This commit is contained in:
Puru Gupta 2023-01-06 15:03:13 +05:30 committed by hasura-bot
parent f047b7dd17
commit bf201e534c
4 changed files with 175 additions and 263 deletions

View File

@ -58,10 +58,10 @@ import Harness.Http qualified as Http
import Harness.Logging
import Harness.Quoter.Yaml (fromYaml, yaml)
import Harness.TestEnvironment (Server (..), TestEnvironment (..), getServer, serverUrl, testLogMessage)
import Hasura.App (Loggers (..), ServeCtx (..))
import Hasura.App qualified as App
import Hasura.Logging (Hasura)
import Hasura.Prelude
import Hasura.Server.App (Loggers (..), ServerCtx (..))
import Hasura.Server.Init (PostgresConnInfo (..), ServeOptions (..), unsafePort)
import Hasura.Server.Metrics (ServerMetricsSpec, createServerMetrics)
import Hasura.Server.Prometheus (makeDummyPrometheusMetrics)
@ -320,24 +320,20 @@ runApp serveOptions = do
liftIO $ createServerMetrics $ EKG.subset ServerSubset store
pure (EKG.subset EKG.emptyOf store, serverMetrics)
prometheusMetrics <- makeDummyPrometheusMetrics
runManagedT (App.initialiseServeCtx env globalCtx serveOptions serverMetrics) $ \serveCtx ->
runManagedT (App.initialiseServerCtx env globalCtx serveOptions Nothing serverMetrics prometheusMetrics sampleAlways) $ \serverCtx@ServerCtx {..} ->
do
let Loggers _ _logger pgLogger = _scLoggers serveCtx
flip App.runPGMetadataStorageAppT (_scMetadataDbPool serveCtx, pgLogger)
let Loggers _ _ pgLogger = scLoggers
flip App.runPGMetadataStorageAppT (scMetadataDbPool, pgLogger)
. lowerManagedT
$ do
App.runHGEServer
(const $ pure ())
env
serveOptions
serveCtx
serverCtx
initTime
Nothing
serverMetrics
ekgStore
Nothing
prometheusMetrics
sampleAlways
-- | Used only for 'runApp' above.
data TestMetricsSpec name metricType tags

View File

@ -22,6 +22,7 @@ import Hasura.GC qualified as GC
import Hasura.Logging (Hasura, LogLevel (..), defaultEnabledEngineLogTypes)
import Hasura.Prelude
import Hasura.RQL.DDL.Schema
import Hasura.Server.App (Loggers (..), ServerCtx (..))
import Hasura.Server.Init
import Hasura.Server.Metrics (ServerMetricsSpec, createServerMetrics)
import Hasura.Server.Migrate (downgradeCatalog)
@ -66,32 +67,26 @@ runApp env (HGEOptions rci metadataDbUrl hgeCmd) = do
-- It'd be nice if we didn't have to call runManagedT twice here, but
-- there is a data dependency problem since the call to runPGMetadataStorageApp
-- below depends on serveCtx.
runManagedT (initialiseServeCtx env globalCtx serveOptions serverMetrics) $ \serveCtx -> do
-- below depends on serverCtx.
runManagedT (initialiseServerCtx env globalCtx serveOptions Nothing serverMetrics prometheusMetrics sampleAlways) $ \serverCtx@ServerCtx {..} -> do
-- Catches the SIGTERM signal and initiates a graceful shutdown.
-- Graceful shutdown for regular HTTP requests is already implemented in
-- Warp, and is triggered by invoking the 'closeSocket' callback.
-- We only catch the SIGTERM signal once, that is, if the user hits CTRL-C
-- once again, we terminate the process immediately.
-- The function is written in this style to avoid the shutdown
-- handler retaining a reference to the entire serveCtx (see #344)
-- If you modify this code then you should check the core to see
-- that serveCtx is not retained.
_ <- case serveCtx of
ServeCtx {_scShutdownLatch} ->
liftIO $ do
void $ Signals.installHandler Signals.sigTERM (Signals.CatchOnce (shutdownGracefully _scShutdownLatch)) Nothing
void $ Signals.installHandler Signals.sigINT (Signals.CatchOnce (shutdownGracefully _scShutdownLatch)) Nothing
liftIO $ do
void $ Signals.installHandler Signals.sigTERM (Signals.CatchOnce (shutdownGracefully scShutdownLatch)) Nothing
void $ Signals.installHandler Signals.sigINT (Signals.CatchOnce (shutdownGracefully scShutdownLatch)) Nothing
let Loggers _ logger pgLogger = _scLoggers serveCtx
let Loggers _ logger pgLogger = scLoggers
_idleGCThread <-
C.forkImmortal "ourIdleGC" logger $
GC.ourIdleGC logger (seconds 0.3) (seconds 10) (seconds 60)
flip runPGMetadataStorageAppT (_scMetadataDbPool serveCtx, pgLogger) . lowerManagedT $ do
runHGEServer (const $ pure ()) env serveOptions serveCtx initTime Nothing serverMetrics ekgStore Nothing prometheusMetrics sampleAlways
flip runPGMetadataStorageAppT (scMetadataDbPool, pgLogger) . lowerManagedT $ do
runHGEServer (const $ pure ()) env serveOptions serverCtx initTime Nothing ekgStore
HCExport -> do
GlobalCtx {..} <- initGlobalCtx env metadataDbUrl rci
res <- runTxWithMinimalPool _gcMetadataDbConnInfo fetchMetadataFromCatalog

View File

@ -5,17 +5,17 @@
-- | Imported by 'server/src-exec/Main.hs'.
module Hasura.App
( ExitCode (DatabaseMigrationError, DowngradeProcessError, MetadataCleanError, MetadataExportError, SchemaCacheInitError),
( ExitCode (AuthConfigurationError, DatabaseMigrationError, DowngradeProcessError, MetadataCleanError, MetadataExportError, SchemaCacheInitError),
ExitException (ExitException),
GlobalCtx (..),
Loggers (..),
PGMetadataStorageAppT (runPGMetadataStorageAppT),
ServeCtx (ServeCtx, _scLoggers, _scMetadataDbPool, _scShutdownLatch),
accessDeniedErrMsg,
flushLogger,
getCatalogStateTx,
initGlobalCtx,
initialiseServeCtx,
initAuthMode,
initialiseServerCtx,
initSubscriptionsState,
migrateCatalogSchema,
mkLoggers,
mkPGLogger,
@ -86,6 +86,7 @@ import Hasura.GraphQL.Execute.Action
import Hasura.GraphQL.Execute.Action.Subscription
import Hasura.GraphQL.Execute.Backend qualified as EB
import Hasura.GraphQL.Execute.Subscription.Poll qualified as ES
import Hasura.GraphQL.Execute.Subscription.State qualified as ES
import Hasura.GraphQL.Logging (MonadQueryLog (..))
import Hasura.GraphQL.Schema.Options qualified as Options
import Hasura.GraphQL.Transport.HTTP
@ -142,10 +143,10 @@ import Hasura.Server.Version
import Hasura.Session
import Hasura.ShutdownLatch
import Hasura.Tracing qualified as Tracing
import Network.HTTP.Client qualified as HTTP
import Network.HTTP.Client.Blocklisting (Blocklist)
import Network.HTTP.Client.CreateManager (mkHttpManager)
import Network.HTTP.Client.Manager (HasHttpManagerM (..))
import Network.HTTP.Client.Transformable qualified as HTTP
import Network.Wai (Application)
import Network.Wai.Handler.Warp qualified as Warp
import Options.Applicative
@ -268,26 +269,6 @@ initGlobalCtx env metadataDbUrl defaultPgConnInfo = do
let mdConnInfo = mkConnInfoFromMDb mdUrl
mkGlobalCtx mdConnInfo (Just (dbUrl, srcConnInfo))
-- | Context required for the 'serve' CLI command.
data ServeCtx = ServeCtx
{ _scHttpManager :: HTTP.Manager,
_scInstanceId :: InstanceId,
_scLoggers :: Loggers,
_scEnabledLogTypes :: HashSet (EngineLogType Hasura),
_scMetadataDbPool :: PG.PGPool,
_scShutdownLatch :: ShutdownLatch,
_scSchemaCacheRef :: SchemaCacheRef,
_scMetaVersionRef :: STM.TMVar MetadataResourceVersion
}
-- | Collection of the LoggerCtx, the regular Logger and the PGLogger
-- TODO (from master): better naming?
data Loggers = Loggers
{ _lsLoggerCtx :: !(LoggerCtx Hasura),
_lsLogger :: !(Logger Hasura),
_lsPgLogger :: !PG.PGLogger
}
-- | An application with Postgres database as a metadata storage
newtype PGMetadataStorageAppT m a = PGMetadataStorageAppT {runPGMetadataStorageAppT :: (PG.PGPool, PG.PGLogger) -> m a}
deriving
@ -321,15 +302,51 @@ resolvePostgresConnInfo env dbUrlConf maybeRetries = do
where
retries = fromMaybe 1 maybeRetries
initAuthMode ::
(C.ForkableMonadIO m, Tracing.HasReporter m) =>
ServeOptions impl ->
HTTP.Manager ->
Logger Hasura ->
m AuthMode
initAuthMode ServeOptions {..} httpManager logger = do
authModeRes <-
runExceptT $
setupAuthMode
soAdminSecret
soAuthHook
soJwtSecret
soUnAuthRole
logger
httpManager
authMode <- onLeft authModeRes (throwErrExit AuthConfigurationError . T.unpack)
-- forking a dedicated polling thread to dynamically get the latest JWK settings
-- set by the user and update the JWK accordingly. This will help in applying the
-- updates without restarting HGE.
_ <- C.forkImmortal "update JWK" logger $ updateJwkCtx authMode httpManager logger
return authMode
initSubscriptionsState ::
ServeOptions impl ->
Logger Hasura ->
Maybe ES.SubscriptionPostPollHook ->
IO ES.SubscriptionsState
initSubscriptionsState ServeOptions {..} logger liveQueryHook = ES.initSubscriptionsState soLiveQueryOpts soStreamingQueryOpts postPollHook
where
postPollHook = fromMaybe (ES.defaultSubscriptionPostPollHook logger) liveQueryHook
-- | Initializes or migrates the catalog and returns the context required to start the server.
initialiseServeCtx ::
initialiseServerCtx ::
(C.ForkableMonadIO m, MonadCatch m) =>
Env.Environment ->
GlobalCtx ->
ServeOptions Hasura ->
Maybe ES.SubscriptionPostPollHook ->
ServerMetrics ->
ManagedT m ServeCtx
initialiseServeCtx env GlobalCtx {..} so@ServeOptions {..} serverMetrics = do
PrometheusMetrics ->
Tracing.SamplingPolicy ->
ManagedT m ServerCtx
initialiseServerCtx env GlobalCtx {..} serveOptions@ServeOptions {..} liveQueryHook serverMetrics prometheusMetrics traceSamplingPolicy = do
instanceId <- liftIO generateInstanceId
latch <- liftIO newShutdownLatch
loggers@(Loggers loggerCtx logger pgLogger) <- mkLoggers soEnabledLogTypes soLogLevel
@ -343,7 +360,7 @@ initialiseServeCtx env GlobalCtx {..} so@ServeOptions {..} serverMetrics = do
slInfo = A.toJSON errMsg
}
-- log serve options
unLogger logger $ serveOptsToLog so
unLogger logger $ serveOptsToLog serveOptions
-- log postgres connection info
unLogger logger $ connInfoToLog _gcMetadataDbConnInfo
@ -414,16 +431,40 @@ initialiseServeCtx env GlobalCtx {..} so@ServeOptions {..} serverMetrics = do
srvMgr <- liftIO $ mkHttpManager (readTlsAllowlist schemaCacheRef) mempty
authMode <- liftIO $ initAuthMode serveOptions srvMgr logger
subscriptionsState <- liftIO $ initSubscriptionsState serveOptions logger liveQueryHook
pure $
ServeCtx
srvMgr
instanceId
loggers
soEnabledLogTypes
metadataDbPool
latch
schemaCacheRef
metaVersionRef
ServerCtx
{ scLoggers = loggers,
scCacheRef = schemaCacheRef,
scAuthMode = authMode,
scManager = srvMgr,
scSQLGenCtx = sqlGenCtx,
scEnabledAPIs = soEnabledAPIs,
scInstanceId = instanceId,
scSubscriptionState = subscriptionsState,
scEnableAllowlist = soEnableAllowlist,
scEnvironment = env,
scResponseInternalErrorsConfig = soResponseInternalErrorsConfig,
scRemoteSchemaPermsCtx = soEnableRemoteSchemaPermissions,
scFunctionPermsCtx = soInferFunctionPermissions,
scEnableMaintenanceMode = soEnableMaintenanceMode,
scExperimentalFeatures = soExperimentalFeatures,
scLoggingSettings = LoggingSettings soEnabledLogTypes soEnableMetadataQueryLogging,
scEventingMode = soEventingMode,
scEnableReadOnlyMode = soReadOnlyMode,
scDefaultNamingConvention = soDefaultNamingConvention,
scServerMetrics = serverMetrics,
scMetadataDefaults = soMetadataDefaults,
scEnabledLogTypes = soEnabledLogTypes,
scMetadataDbPool = metadataDbPool,
scShutdownLatch = latch,
scMetaVersionRef = metaVersionRef,
scPrometheusMetrics = prometheusMetrics,
scTraceSamplingPolicy = traceSamplingPolicy
}
mkLoggers ::
(MonadIO m, MonadBaseControl IO m) =>
@ -558,24 +599,18 @@ runHGEServer ::
(ServerCtx -> Spock.SpockT m ()) ->
Env.Environment ->
ServeOptions impl ->
ServeCtx ->
-- and mutations
ServerCtx ->
-- | start time
UTCTime ->
Maybe ES.SubscriptionPostPollHook ->
ServerMetrics ->
EKG.Store EKG.EmptyMetrics ->
-- | A hook which can be called to indicate when the server is started succesfully
Maybe (IO ()) ->
PrometheusMetrics ->
Tracing.SamplingPolicy ->
EKG.Store EKG.EmptyMetrics ->
ManagedT m ()
runHGEServer setupHook env serveOptions serveCtx initTime postPollHook serverMetrics ekgStore startupStatusHook prometheusMetrics traceSamplingPolicy = do
runHGEServer setupHook env serveOptions serverCtx@ServerCtx {..} initTime startupStatusHook ekgStore = do
waiApplication <-
mkHGEServer setupHook env serveOptions serveCtx postPollHook serverMetrics ekgStore prometheusMetrics traceSamplingPolicy
mkHGEServer setupHook env serveOptions serverCtx ekgStore
let logger = _lsLogger $ _scLoggers serveCtx
let logger = _lsLogger $ scLoggers
-- `startupStatusHook`: add `Service started successfully` message to config_status
-- table when a tenant starts up in multitenant
let warpSettings :: Warp.Settings
@ -595,12 +630,12 @@ runHGEServer setupHook env serveOptions serveCtx initTime postPollHook serverMet
( \unmask ->
bracket_
( do
EKG.Gauge.inc (smWarpThreads serverMetrics)
incWarpThreads (pmConnections prometheusMetrics)
EKG.Gauge.inc (smWarpThreads scServerMetrics)
incWarpThreads (pmConnections scPrometheusMetrics)
)
( do
EKG.Gauge.dec (smWarpThreads serverMetrics)
decWarpThreads (pmConnections prometheusMetrics)
EKG.Gauge.dec (smWarpThreads scServerMetrics)
decWarpThreads (pmConnections scPrometheusMetrics)
)
(f unmask)
)
@ -608,7 +643,7 @@ runHGEServer setupHook env serveOptions serveCtx initTime postPollHook serverMet
shutdownHandler :: IO () -> IO ()
shutdownHandler closeSocket =
LA.link =<< LA.async do
waitForShutdown $ _scShutdownLatch serveCtx
waitForShutdown $ scShutdownLatch
unLogger logger $ mkGenericLog @Text LevelInfo "server" "gracefully shutting down server"
closeSocket
@ -654,16 +689,10 @@ mkHGEServer ::
(ServerCtx -> Spock.SpockT m ()) ->
Env.Environment ->
ServeOptions impl ->
ServeCtx ->
-- and mutations
Maybe ES.SubscriptionPostPollHook ->
ServerMetrics ->
ServerCtx ->
EKG.Store EKG.EmptyMetrics ->
PrometheusMetrics ->
Tracing.SamplingPolicy ->
ManagedT m Application
mkHGEServer setupHook env ServeOptions {..} ServeCtx {..} postPollHook serverMetrics ekgStore prometheusMetrics traceSamplingPolicy = do
mkHGEServer setupHook env ServeOptions {..} serverCtx@ServerCtx {..} ekgStore = do
-- Comment this to enable expensive assertions from "GHC.AssertNF". These
-- will log lines to STDOUT containing "not in normal form". In the future we
-- could try to integrate this into our tests. For now this is a development
@ -681,25 +710,7 @@ mkHGEServer setupHook env ServeOptions {..} ServeCtx {..} postPollHook serverMet
| otherwise = Options.DisableBigQueryStringNumericInput
sqlGenCtx = SQLGenCtx soStringifyNum soDangerousBooleanCollapse optimizePermissionFilters bigqueryStringNumericInput
Loggers loggerCtx logger _ = _scLoggers
authModeRes <-
lift $
runExceptT $
setupAuthMode
soAdminSecret
soAuthHook
soJwtSecret
soUnAuthRole
logger
_scHttpManager
authMode <- onLeft authModeRes (throwErrExit AuthConfigurationError . T.unpack)
-- forking a dedicated polling thread to dynamically get the latest JWK settings
-- set by the user and update the JWK accordingly. This will help in applying the
-- updates without restarting HGE.
_ <- C.forkManagedT "update JWK" logger $ updateJwkCtx authMode _scHttpManager logger
Loggers loggerCtx logger _ = scLoggers
HasuraApp app cacheRef actionSubState stopWsServer <-
lift $
@ -707,41 +718,20 @@ mkHGEServer setupHook env ServeOptions {..} ServeCtx {..} postPollHook serverMet
mkWaiApp
setupHook
env
logger
sqlGenCtx
soEnableAllowlist
_scHttpManager
authMode
soCorsConfig
soEnableConsole
soConsoleAssetsDir
soConsoleSentryDsn
soEnableTelemetry
_scInstanceId
soEnabledAPIs
soLiveQueryOpts
soStreamingQueryOpts
soResponseInternalErrorsConfig
postPollHook
_scSchemaCacheRef
ekgStore
serverMetrics
prometheusMetrics
soEnableRemoteSchemaPermissions
soInferFunctionPermissions
scCacheRef
soConnectionOptions
soWebSocketKeepAlive
soEnableMaintenanceMode
soEventingMode
soReadOnlyMode
soExperimentalFeatures
_scEnabledLogTypes
scEnabledLogTypes
serverCtx
soWebSocketConnectionInitTimeout
soEnableMetadataQueryLogging
soDefaultNamingConvention
soMetadataDefaults
traceSamplingPolicy
ekgStore
-- Init ServerConfigCtx
let serverConfigCtx =
ServerConfigCtx
soInferFunctionPermissions
@ -770,10 +760,10 @@ mkHGEServer setupHook env ServeOptions {..} ServeCtx {..} postPollHook serverMet
_ <-
startSchemaSyncProcessorThread
logger
_scHttpManager
_scMetaVersionRef
scManager
scMetaVersionRef
cacheRef
_scInstanceId
scInstanceId
serverConfigCtx
newLogTVar
@ -803,7 +793,7 @@ mkHGEServer setupHook env ServeOptions {..} ServeCtx {..} postPollHook serverMet
_updateThread <-
C.forkManagedT "checkForUpdates" logger $
liftIO $
checkForUpdates loggerCtx _scHttpManager
checkForUpdates loggerCtx scManager
-- Start a background thread for source pings
_sourcePingPoller <-
@ -826,13 +816,13 @@ mkHGEServer setupHook env ServeOptions {..} ServeCtx {..} postPollHook serverMet
runMetadataStorageT getMetadataDbUid
>>= (`onLeft` throwErrJExit DatabaseMigrationError)
pgVersion <-
liftIO (runExceptT $ PG.runTx _scMetadataDbPool (PG.ReadCommitted, Nothing) $ getPgVersion)
liftIO (runExceptT $ PG.runTx scMetadataDbPool (PG.ReadCommitted, Nothing) $ getPgVersion)
>>= (`onLeft` throwErrJExit DatabaseMigrationError)
telemetryThread <-
C.forkManagedT "runTelemetry" logger $
liftIO $
runTelemetry logger _scHttpManager (getSchemaCache cacheRef) dbUid _scInstanceId pgVersion soExperimentalFeatures
runTelemetry logger scManager (getSchemaCache cacheRef) dbUid scInstanceId pgVersion soExperimentalFeatures
return $ Just telemetryThread
else return Nothing
@ -962,12 +952,12 @@ mkHGEServer setupHook env ServeOptions {..} ServeCtx {..} postPollHook serverMet
(C.ThreadShutdown (liftIO eventsGracefulShutdownAction))
$ processEventQueue
logger
_scHttpManager
scManager
(getSchemaCache cacheRef)
eventEngineCtx
lockedEventsCtx
serverMetrics
(pmEventTriggerMetrics prometheusMetrics)
scServerMetrics
(pmEventTriggerMetrics scPrometheusMetrics)
soEnableMaintenanceMode
startAsyncActionsPollerThread logger lockedEventsCtx cacheRef actionSubState = do
@ -997,8 +987,8 @@ mkHGEServer setupHook env ServeOptions {..} ServeCtx {..} postPollHook serverMet
logger
(getSchemaCache cacheRef)
(leActionEvents lockedEventsCtx)
_scHttpManager
prometheusMetrics
scManager
scPrometheusMetrics
sleepTime
Nothing
@ -1032,8 +1022,8 @@ mkHGEServer setupHook env ServeOptions {..} ServeCtx {..} postPollHook serverMet
$ processScheduledTriggers
env
logger
_scHttpManager
prometheusMetrics
scManager
scPrometheusMetrics
(getSchemaCache cacheRef)
lockedEventsCtx

View File

@ -7,9 +7,10 @@ module Hasura.Server.App
Handler,
HandlerCtx (hcReqHeaders, hcServerCtx, hcUser),
HasuraApp (HasuraApp),
Loggers (..),
MonadConfigApiHandler (..),
MonadMetadataApiAuthorization (..),
ServerCtx (scManager, scLoggingSettings, scEnabledAPIs),
ServerCtx (..),
boolToText,
configApiGetHandler,
isAdminSecretSet,
@ -22,6 +23,7 @@ module Hasura.Server.App
where
import Control.Concurrent.Async.Lifted.Safe qualified as LA
import Control.Concurrent.STM qualified as STM
import Control.Exception (IOException, try)
import Control.Monad.Stateless
import Control.Monad.Trans.Control (MonadBaseControl)
@ -43,6 +45,7 @@ import Data.Text.Conversions (convertText)
import Data.Text.Extended
import Data.Text.Lazy qualified as LT
import Data.Text.Lazy.Encoding qualified as TL
import Database.PG.Query qualified as PG
import GHC.Stats.Extended qualified as RTS
import Hasura.Backends.DataConnector.API (openApiSchema)
import Hasura.Backends.Postgres.Execute.Types
@ -50,8 +53,6 @@ import Hasura.Base.Error
import Hasura.EncJSON
import Hasura.GraphQL.Execute qualified as E
import Hasura.GraphQL.Execute.Backend qualified as EB
import Hasura.GraphQL.Execute.Subscription.Options qualified as ES
import Hasura.GraphQL.Execute.Subscription.Poll qualified as ES
import Hasura.GraphQL.Execute.Subscription.State qualified as ES
import Hasura.GraphQL.Explain qualified as GE
import Hasura.GraphQL.Logging (MonadQueryLog)
@ -99,6 +100,7 @@ import Hasura.Server.Types
import Hasura.Server.Utils
import Hasura.Server.Version
import Hasura.Session
import Hasura.ShutdownLatch
import Hasura.Tracing qualified as Tracing
import Network.HTTP.Client qualified as HTTP
import Network.HTTP.Types qualified as HTTP
@ -115,7 +117,7 @@ import Web.Spock.Core ((<//>))
import Web.Spock.Core qualified as Spock
data ServerCtx = ServerCtx
{ scLogger :: !(L.Logger L.Hasura),
{ scLoggers :: !Loggers,
scCacheRef :: !SchemaCacheRef,
scAuthMode :: !AuthMode,
scManager :: !HTTP.Manager,
@ -124,7 +126,6 @@ data ServerCtx = ServerCtx
scInstanceId :: !InstanceId,
scSubscriptionState :: !ES.SubscriptionsState,
scEnableAllowlist :: !Bool,
scEkgStore :: !(EKG.Store EKG.EmptyMetrics),
scResponseInternalErrorsConfig :: !ResponseInternalErrorsConfig,
scEnvironment :: !Env.Environment,
scRemoteSchemaPermsCtx :: !Options.RemoteSchemaPermissions,
@ -135,9 +136,22 @@ data ServerCtx = ServerCtx
scEventingMode :: !EventingMode,
scEnableReadOnlyMode :: !ReadOnlyMode,
scDefaultNamingConvention :: !(Maybe NamingCase),
scPrometheusMetrics :: !PrometheusMetrics,
scServerMetrics :: !ServerMetrics,
scMetadataDefaults :: !MetadataDefaults,
scTraceSamplingPolicy :: !Tracing.SamplingPolicy
scEnabledLogTypes :: HashSet (L.EngineLogType L.Hasura),
scMetadataDbPool :: PG.PGPool,
scShutdownLatch :: ShutdownLatch,
scMetaVersionRef :: STM.TMVar MetadataResourceVersion,
scPrometheusMetrics :: PrometheusMetrics,
scTraceSamplingPolicy :: Tracing.SamplingPolicy
}
-- | Collection of the LoggerCtx, the regular Logger and the PGLogger
-- TODO (from master): better naming?
data Loggers = Loggers
{ _lsLoggerCtx :: !(L.LoggerCtx L.Hasura),
_lsLogger :: !(L.Logger L.Hasura),
_lsPgLogger :: !PG.PGLogger
}
data HandlerCtx = HandlerCtx
@ -315,7 +329,7 @@ mkSpockAction serverCtx@ServerCtx {..} qErrEncoder qErrModifier apiHandler = do
runMetadataStorageT $ flip runReaderT handlerCtx $ runResourceLimits handlerLimit $ handler
getInfo parsedRequest = do
authenticationResp <- lift (resolveUserInfo scLogger scManager headers scAuthMode parsedRequest)
authenticationResp <- lift (resolveUserInfo (_lsLogger scLoggers) scManager headers scAuthMode parsedRequest)
authInfo <- onLeft authenticationResp (logErrorAndResp Nothing requestId req (reqBody, Nothing) False origHeaders (ExtraUserInfo Nothing) . qErrModifier)
let (userInfo, _, authHeaders, extraUserInfo) = authInfo
pure
@ -382,7 +396,7 @@ mkSpockAction serverCtx@ServerCtx {..} qErrEncoder qErrModifier apiHandler = do
Spock.ActionCtxT ctx m3 a3
logErrorAndResp userInfo reqId waiReq req includeInternal headers extraUserInfo qErr = do
let httpLogMetadata = buildHttpLogMetadata @m3 emptyHttpLogGraphQLInfo extraUserInfo
lift $ logHttpError scLogger scLoggingSettings userInfo reqId waiReq req qErr headers httpLogMetadata
lift $ logHttpError (_lsLogger scLoggers) scLoggingSettings userInfo reqId waiReq req qErr headers httpLogMetadata
Spock.setStatus $ qeStatus qErr
Spock.json $ qErrEncoder includeInternal qErr
@ -394,7 +408,7 @@ mkSpockAction serverCtx@ServerCtx {..} qErrEncoder qErrModifier apiHandler = do
encodingHeader = maybeToList (contentEncodingHeader <$> encodingType)
reqIdHeader = (requestIdHeader, txtToBs $ unRequestId reqId)
allRespHeaders = pure reqIdHeader <> encodingHeader <> respHeaders <> authHdrs
lift $ logHttpSuccess scLogger scLoggingSettings userInfo reqId waiReq req respBytes compressedResp qTime encodingType reqHeaders httpLoggingMetadata
lift $ logHttpSuccess (_lsLogger scLoggers) scLoggingSettings userInfo reqId waiReq req respBytes compressedResp qTime encodingType reqHeaders httpLoggingMetadata
mapM_ setHeader allRespHeaders
Spock.lazyBytes compressedResp
@ -414,7 +428,7 @@ v1QueryHandler ::
v1QueryHandler query = do
(liftEitherM . authorizeV1QueryApi query) =<< ask
scRef <- asks (scCacheRef . hcServerCtx)
logger <- asks (scLogger . hcServerCtx)
logger <- asks (_lsLogger . scLoggers . hcServerCtx)
res <- bool (fst <$> (action logger)) (withSchemaCacheUpdate scRef logger Nothing (action logger)) $ queryModifiesSchemaCache query
return $ HttpResponse res []
where
@ -476,7 +490,7 @@ v1MetadataHandler query = Tracing.trace "Metadata" $ do
_sccSQLGenCtx <- asks (scSQLGenCtx . hcServerCtx)
env <- asks (scEnvironment . hcServerCtx)
instanceId <- asks (scInstanceId . hcServerCtx)
logger <- asks (scLogger . hcServerCtx)
logger <- asks (_lsLogger . scLoggers . hcServerCtx)
_sccRemoteSchemaPermsCtx <- asks (scRemoteSchemaPermsCtx . hcServerCtx)
_sccFunctionPermsCtx <- asks (scFunctionPermsCtx . hcServerCtx)
_sccExperimentalFeatures <- asks (scExperimentalFeatures . hcServerCtx)
@ -517,7 +531,7 @@ v2QueryHandler ::
v2QueryHandler query = Tracing.trace "v2 Query" $ do
(liftEitherM . authorizeV2QueryApi query) =<< ask
scRef <- asks (scCacheRef . hcServerCtx)
logger <- asks (scLogger . hcServerCtx)
logger <- asks (_lsLogger . scLoggers . hcServerCtx)
res <-
bool (fst <$> dbAction) (withSchemaCacheUpdate scRef logger Nothing dbAction) $
V2Q.queryModifiesSchema query
@ -575,7 +589,7 @@ v1Alpha1GQHandler queryType query = do
reqHeaders <- asks hcReqHeaders
ipAddress <- asks hcSourceIpAddress
requestId <- asks hcRequestId
logger <- asks (scLogger . hcServerCtx)
logger <- asks (_lsLogger . scLoggers . hcServerCtx)
responseErrorsConfig <- asks (scResponseInternalErrorsConfig . hcServerCtx)
env <- asks (scEnvironment . hcServerCtx)
@ -595,7 +609,7 @@ mkExecutionContext = do
(sc, scVer) <- liftIO $ readSchemaCacheRef scRef
sqlGenCtx <- asks (scSQLGenCtx . hcServerCtx)
enableAL <- asks (scEnableAllowlist . hcServerCtx)
logger <- asks (scLogger . hcServerCtx)
logger <- asks (_lsLogger . scLoggers . hcServerCtx)
readOnlyMode <- asks (scEnableReadOnlyMode . hcServerCtx)
prometheusMetrics <- asks (scPrometheusMetrics . hcServerCtx)
pure $ E.ExecutionCtx logger sqlGenCtx (lastBuiltSchemaCache sc) scVer manager enableAL readOnlyMode prometheusMetrics
@ -776,15 +790,6 @@ mkWaiApp ::
(ServerCtx -> Spock.SpockT m ()) ->
-- | Set of environment variables for reference in UIs
Env.Environment ->
-- | a 'L.Hasura' specific logger
L.Logger L.Hasura ->
SQLGenCtx ->
-- | is AllowList enabled - TODO: change this boolean to sumtype
Bool ->
-- | HTTP manager so that we can re-use sessions
HTTP.Manager ->
-- | 'AuthMode' in which the application should operate in
AuthMode ->
CorsConfig ->
-- | is console enabled - TODO: better type
Bool ->
@ -794,136 +799,60 @@ mkWaiApp ::
Maybe Text ->
-- | is telemetry enabled
Bool ->
-- | each application, when run, gets an 'InstanceId'. this is used at various places including
-- schema syncing and telemetry
InstanceId ->
-- | set of the enabled 'API's
S.HashSet API ->
ES.LiveQueriesOptions ->
ES.StreamQueriesOptions ->
ResponseInternalErrorsConfig ->
Maybe ES.SubscriptionPostPollHook ->
SchemaCacheRef ->
EKG.Store EKG.EmptyMetrics ->
ServerMetrics ->
PrometheusMetrics ->
Options.RemoteSchemaPermissions ->
Options.InferFunctionPermissions ->
WS.ConnectionOptions ->
KeepAliveDelay ->
MaintenanceMode () ->
EventingMode ->
ReadOnlyMode ->
-- | Set of the enabled experimental features
S.HashSet ExperimentalFeature ->
S.HashSet (L.EngineLogType L.Hasura) ->
ServerCtx ->
WSConnectionInitTimeout ->
-- | is metadata query logging in http-log enabled
MetadataQueryLoggingMode ->
-- | default naming convention
Maybe NamingCase ->
-- | default metadata entries
MetadataDefaults ->
Tracing.SamplingPolicy ->
EKG.Store EKG.EmptyMetrics ->
m HasuraApp
mkWaiApp
setupHook
env
logger
sqlGenCtx
enableAL
httpManager
mode
corsCfg
enableConsole
consoleAssetsDir
consoleSentryDsn
enableTelemetry
instanceId
apis
lqOpts
streamQOpts
responseErrorsConfig
liveQueryHook
schemaCacheRef
ekgStore
serverMetrics
prometheusMetrics
enableRSPermsCtx
functionPermsCtx
connectionOptions
keepAliveDelay
maintenanceMode
eventingMode
readOnlyMode
experimentalFeatures
enabledLogTypes
serverCtx@ServerCtx {..}
wsConnInitTimeout
enableMetadataQueryLogging
defaultNC
metadataDefaults
traceSamplingPolicy = do
ekgStore = do
let getSchemaCache' = first lastBuiltSchemaCache <$> readSchemaCacheRef schemaCacheRef
let corsPolicy = mkDefaultCorsPolicy corsCfg
postPollHook = fromMaybe (ES.defaultSubscriptionPostPollHook logger) liveQueryHook
subscriptionsState <- liftIO $ ES.initSubscriptionsState lqOpts streamQOpts postPollHook
wsServerEnv <-
WS.createWSServerEnv
logger
subscriptionsState
(_lsLogger scLoggers)
scSubscriptionState
getSchemaCache'
httpManager
scManager
corsPolicy
sqlGenCtx
readOnlyMode
enableAL
scSQLGenCtx
scEnableReadOnlyMode
scEnableAllowlist
keepAliveDelay
serverMetrics
prometheusMetrics
traceSamplingPolicy
let serverCtx =
ServerCtx
{ scLogger = logger,
scCacheRef = schemaCacheRef,
scAuthMode = mode,
scManager = httpManager,
scSQLGenCtx = sqlGenCtx,
scEnabledAPIs = apis,
scInstanceId = instanceId,
scSubscriptionState = subscriptionsState,
scEnableAllowlist = enableAL,
scEkgStore = ekgStore,
scEnvironment = env,
scResponseInternalErrorsConfig = responseErrorsConfig,
scRemoteSchemaPermsCtx = enableRSPermsCtx,
scFunctionPermsCtx = functionPermsCtx,
scEnableMaintenanceMode = maintenanceMode,
scExperimentalFeatures = experimentalFeatures,
scLoggingSettings = LoggingSettings enabledLogTypes enableMetadataQueryLogging,
scEventingMode = eventingMode,
scEnableReadOnlyMode = readOnlyMode,
scDefaultNamingConvention = defaultNC,
scPrometheusMetrics = prometheusMetrics,
scMetadataDefaults = metadataDefaults,
scTraceSamplingPolicy = traceSamplingPolicy
}
scServerMetrics
scPrometheusMetrics
scTraceSamplingPolicy
spockApp <- liftWithStateless $ \lowerIO ->
Spock.spockAsApp $
Spock.spockT lowerIO $
httpApp setupHook corsCfg serverCtx enableConsole consoleAssetsDir consoleSentryDsn enableTelemetry
httpApp setupHook corsCfg serverCtx enableConsole consoleAssetsDir consoleSentryDsn enableTelemetry ekgStore
let wsServerApp = WS.createWSServerApp env enabledLogTypes mode wsServerEnv wsConnInitTimeout -- TODO: Lyndon: Can we pass environment through wsServerEnv?
let wsServerApp = WS.createWSServerApp env enabledLogTypes scAuthMode wsServerEnv wsConnInitTimeout -- TODO: Lyndon: Can we pass environment through wsServerEnv?
stopWSServer = WS.stopWSServerApp wsServerEnv
waiApp <- liftWithStateless $ \lowerIO ->
pure $ WSC.websocketsOr connectionOptions (\ip conn -> lowerIO $ wsServerApp ip conn) spockApp
return $ HasuraApp waiApp schemaCacheRef (ES._ssAsyncActions subscriptionsState) stopWSServer
return $ HasuraApp waiApp schemaCacheRef (ES._ssAsyncActions scSubscriptionState) stopWSServer
httpApp ::
forall m.
@ -953,8 +882,9 @@ httpApp ::
Maybe Text ->
Maybe Text ->
Bool ->
EKG.Store EKG.EmptyMetrics ->
Spock.SpockT m ()
httpApp setupHook corsCfg serverCtx enableConsole consoleAssetsDir consoleSentryDsn enableTelemetry = do
httpApp setupHook corsCfg serverCtx enableConsole consoleAssetsDir consoleSentryDsn enableTelemetry ekgStore = do
-- Additional spock action to run
setupHook serverCtx
@ -1085,7 +1015,8 @@ httpApp setupHook corsCfg serverCtx enableConsole consoleAssetsDir consoleSentry
Spock.post "v1/graphql" $
spockAction GH.encodeGQErr allMod200 $
mkGQLRequestHandler $
mkGQLAPIRespHandler v1GQHandler
mkGQLAPIRespHandler $
v1GQHandler
Spock.post "v1beta1/relay" $
spockAction GH.encodeGQErr allMod200 $
@ -1110,7 +1041,7 @@ httpApp setupHook corsCfg serverCtx enableConsole consoleAssetsDir consoleSentry
spockAction encodeQErr id $
mkGetHandler $ do
onlyAdmin
respJ <- liftIO $ EKG.sampleAll $ scEkgStore serverCtx
respJ <- liftIO $ EKG.sampleAll ekgStore
return (emptyHttpLogGraphQLInfo, JSONResp $ HttpResponse (encJFromJValue $ EKG.sampleToJson respJ) [])
-- This deprecated endpoint used to show the query plan cache pre-PDV.
-- Eventually this endpoint can be removed.
@ -1150,7 +1081,7 @@ httpApp setupHook corsCfg serverCtx enableConsole consoleAssetsDir consoleSentry
qErr = err404 NotFound "resource does not exist"
raiseGenericApiError logger (scLoggingSettings serverCtx) headers qErr
where
logger = scLogger serverCtx
logger = (_lsLogger . scLoggers) serverCtx
logSuccess msg = do
req <- Spock.request