mirror of
https://github.com/hasura/graphql-engine.git
synced 2024-10-26 10:20:54 +03:00
feat(SqlServer): Configuration option to disable the connection pool
PR-URL: https://github.com/hasura/graphql-engine-mono/pull/9834 Co-authored-by: Samir Talwar <47582+SamirTalwar@users.noreply.github.com> GitOrigin-RevId: 6b7f8bd660ddda0cae3a5457267f5af4906ff65a
This commit is contained in:
parent
58ce99e63a
commit
462abadb8c
@ -191,12 +191,22 @@ and the two generally shouldn't be enabled at the same time.
|
||||
|
||||
## MsSQLPoolSettings {#mssqlpoolsettings}
|
||||
|
||||
Pool settings have two disjoint cases.
|
||||
|
||||
This schema indicates that the source uses a connection pool (the default):
|
||||
|
||||
| Key | Required | Schema | Description |
|
||||
| --------------------- | -------- | --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| max_connections | false | `Integer` | Maximum number of connections to be kept in the pool (default: 50) |
|
||||
| total_max_connections | false | `Integer` | Maximum number of total connections across any number of Hasura Cloud instances (default: 50). Takes precedence over `max_connections` in Cloud projects. _(Only available in Cloud)_ |
|
||||
| idle_timeout | false | `Integer` | The idle timeout (in seconds) per connection (default: 180) |
|
||||
|
||||
This schema indicates that the source does not use a connection pool:
|
||||
|
||||
| Key | Required | Schema | Description |
|
||||
| -------------- | -------- | --------- | ------------------------------------------------------ |
|
||||
| enable | true | `Bool` | Set to `false` to disable the connection pool entirely |
|
||||
|
||||
## PGColumnType {#pgcolumntype}
|
||||
|
||||
<div className="parsed-literal">
|
||||
|
@ -4977,7 +4977,20 @@
|
||||
"type": "string"
|
||||
},
|
||||
"pool_settings": {
|
||||
"$ref": "#/components/schemas/MSSQLPoolSettings"
|
||||
"additionalProperties": true,
|
||||
"anyOf": [
|
||||
{
|
||||
"enum": [
|
||||
{
|
||||
"enable": false
|
||||
}
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/MSSQLPoolSettings"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
|
@ -142,6 +142,7 @@ library
|
||||
Test.Databases.Postgres.JsonbSpec
|
||||
Test.Databases.Postgres.TimestampSpec
|
||||
Test.Databases.Postgres.UniqueConstraintsSpec
|
||||
Test.Databases.SQLServer.ConnectionPoolSpec
|
||||
Test.Databases.SQLServer.DefaultValues.OnConflictSpec
|
||||
Test.Databases.SQLServer.InsertVarcharColumnSpec
|
||||
Test.Databases.SQLServer.VarcharLiteralsSpec
|
||||
|
@ -0,0 +1,67 @@
|
||||
{-# LANGUAGE QuasiQuotes #-}
|
||||
|
||||
-- | Tests that the connection pool can be configured in different ways for SqlServer.
|
||||
module Test.Databases.SQLServer.ConnectionPoolSpec (spec) where
|
||||
|
||||
import Data.Aeson (Value)
|
||||
import Data.List.NonEmpty qualified as NE
|
||||
import Harness.Backend.Sqlserver qualified as Sqlserver
|
||||
import Harness.Constants qualified as Constants
|
||||
import Harness.GraphqlEngine qualified as GraphqlEngine
|
||||
import Harness.Quoter.Yaml (yaml)
|
||||
import Harness.Test.Fixture qualified as Fixture
|
||||
import Harness.TestEnvironment
|
||||
import Harness.Yaml
|
||||
import Hasura.Prelude
|
||||
import Test.Hspec
|
||||
|
||||
spec :: SpecWith GlobalTestEnvironment
|
||||
spec =
|
||||
Fixture.run
|
||||
( NE.fromList
|
||||
[ (Fixture.fixture $ Fixture.Backend Sqlserver.backendTypeMetadata)
|
||||
]
|
||||
)
|
||||
tests
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- Tests
|
||||
|
||||
tests :: SpecWith TestEnvironment
|
||||
tests = do
|
||||
describe "Connection pool" do
|
||||
it "Can be disabled" \testEnvironment -> do
|
||||
GraphqlEngine.setSource testEnvironment (sourceMetadataNoPool testEnvironment) Nothing
|
||||
actual <- GraphqlEngine.exportMetadata testEnvironment
|
||||
|
||||
actual
|
||||
`shouldAtLeastBe` [yaml|
|
||||
sources:
|
||||
- configuration:
|
||||
connection_info:
|
||||
pool_settings:
|
||||
enable: false
|
||||
|]
|
||||
|
||||
sourceMetadataNoPool :: TestEnvironment -> Value
|
||||
sourceMetadataNoPool TestEnvironment {uniqueTestId} =
|
||||
let source = Fixture.backendSourceName Sqlserver.backendTypeMetadata
|
||||
backendType = Fixture.backendTypeString Sqlserver.backendTypeMetadata
|
||||
sourceConfiguration = defaultSourceConfiguration
|
||||
in [yaml|
|
||||
name: *source
|
||||
kind: *backendType
|
||||
tables: []
|
||||
configuration: *sourceConfiguration
|
||||
|]
|
||||
where
|
||||
defaultSourceConfiguration :: Value
|
||||
defaultSourceConfiguration =
|
||||
[yaml|
|
||||
connection_info:
|
||||
database_url: *sqlserverConnectInfo
|
||||
pool_settings:
|
||||
enable: false
|
||||
|]
|
||||
|
||||
sqlserverConnectInfo = Constants.sqlserverConnectInfo uniqueTestId
|
@ -30,21 +30,27 @@ newtype ConnectionString = ConnectionString {unConnectionString :: Text}
|
||||
instance HasCodec ConnectionString where
|
||||
codec = dimapCodec ConnectionString unConnectionString codec
|
||||
|
||||
data ConnectionOptions = ConnectionOptions
|
||||
{ _coConnections :: Int,
|
||||
_coStripes :: Int,
|
||||
_coIdleTime :: Int
|
||||
}
|
||||
data ConnectionOptions
|
||||
= ConnectionOptions
|
||||
{ _coConnections :: Int,
|
||||
_coStripes :: Int,
|
||||
_coIdleTime :: Int
|
||||
}
|
||||
| ConnectionOptionsNoPool
|
||||
deriving (Show, Eq)
|
||||
|
||||
-- | ODBC connection pool
|
||||
newtype MSSQLPool = MSSQLPool (Pool.Pool ODBC.Connection)
|
||||
data MSSQLPool
|
||||
= MSSQLPool (Pool.Pool ODBC.Connection)
|
||||
| MSSQLNoPool (IO ODBC.Connection)
|
||||
|
||||
-- | Initialize an MSSQL pool with given connection configuration
|
||||
initMSSQLPool ::
|
||||
ConnectionString ->
|
||||
ConnectionOptions ->
|
||||
IO MSSQLPool
|
||||
initMSSQLPool (ConnectionString connString) ConnectionOptionsNoPool = do
|
||||
return $ MSSQLNoPool (ODBC.connect connString)
|
||||
initMSSQLPool (ConnectionString connString) ConnectionOptions {..} = do
|
||||
MSSQLPool
|
||||
<$> Pool.createPool
|
||||
@ -58,6 +64,7 @@ initMSSQLPool (ConnectionString connString) ConnectionOptions {..} = do
|
||||
drainMSSQLPool :: MSSQLPool -> IO ()
|
||||
drainMSSQLPool (MSSQLPool pool) =
|
||||
Pool.destroyAllResources pool
|
||||
drainMSSQLPool MSSQLNoPool {} = return ()
|
||||
|
||||
withMSSQLPool ::
|
||||
(MonadBaseControl IO m) =>
|
||||
@ -66,6 +73,8 @@ withMSSQLPool ::
|
||||
m (Either ODBC.ODBCException a)
|
||||
withMSSQLPool (MSSQLPool pool) action = do
|
||||
try $ Pool.withResource pool action
|
||||
withMSSQLPool (MSSQLNoPool connect) action = do
|
||||
try $ bracket (liftBaseWith (const connect)) (\conn -> liftBaseWith (const (ODBC.close conn))) action
|
||||
|
||||
-- | Resize a pool
|
||||
resizePool :: MSSQLPool -> Int -> IO ()
|
||||
@ -74,6 +83,8 @@ resizePool (MSSQLPool pool) resizeTo = do
|
||||
Pool.resizePool pool resizeTo
|
||||
-- Trim pool by destroying excess resources, if any
|
||||
Pool.tryTrimPool pool
|
||||
resizePool (MSSQLNoPool {}) _ = return ()
|
||||
|
||||
getInUseConnections :: MSSQLPool -> IO Int
|
||||
getInUseConnections (MSSQLPool pool) = Pool.getInUseResourceCount $ pool
|
||||
getInUseConnections MSSQLNoPool {} = return 0
|
||||
|
@ -1465,13 +1465,15 @@ mkPgSourceResolver pgLogger env _ config = runExceptT do
|
||||
|
||||
mkMSSQLSourceResolver :: SourceResolver ('MSSQL)
|
||||
mkMSSQLSourceResolver env _name (MSSQLConnConfiguration connInfo _) = runExceptT do
|
||||
let MSSQLConnectionInfo iConnString MSSQLPoolSettings {..} isolationLevel = connInfo
|
||||
connOptions =
|
||||
MSPool.ConnectionOptions
|
||||
{ _coConnections = fromMaybe defaultMSSQLMaxConnections _mpsMaxConnections,
|
||||
_coStripes = 1,
|
||||
_coIdleTime = _mpsIdleTimeout
|
||||
}
|
||||
let MSSQLConnectionInfo iConnString poolSettings isolationLevel = connInfo
|
||||
connOptions = case poolSettings of
|
||||
MSSQLPoolSettings {..} ->
|
||||
MSPool.ConnectionOptions
|
||||
{ _coConnections = fromMaybe defaultMSSQLMaxConnections _mpsMaxConnections,
|
||||
_coStripes = 1,
|
||||
_coIdleTime = _mpsIdleTimeout
|
||||
}
|
||||
MSSQLPoolSettingsNoPool -> MSPool.ConnectionOptionsNoPool
|
||||
(connString, mssqlPool) <- createMSSQLPool iConnString connOptions env
|
||||
let mssqlExecCtx = mkMSSQLExecCtx isolationLevel mssqlPool NeverResizePool
|
||||
numReadReplicas = 0
|
||||
|
@ -99,42 +99,57 @@ instance FromJSON InputConnectionString where
|
||||
s@(String _) -> RawString <$> parseJSON s
|
||||
_ -> fail "one of string or object must be provided"
|
||||
|
||||
data MSSQLPoolSettings = MSSQLPoolSettings
|
||||
{ _mpsMaxConnections :: Maybe Int,
|
||||
_mpsTotalMaxConnections :: Maybe Int,
|
||||
_mpsIdleTimeout :: Int
|
||||
}
|
||||
data MSSQLPoolSettings
|
||||
= MSSQLPoolSettings
|
||||
{ _mpsMaxConnections :: Maybe Int,
|
||||
_mpsTotalMaxConnections :: Maybe Int,
|
||||
_mpsIdleTimeout :: Int
|
||||
}
|
||||
| MSSQLPoolSettingsNoPool
|
||||
deriving (Show, Eq, Generic)
|
||||
|
||||
instance Hashable MSSQLPoolSettings
|
||||
|
||||
instance NFData MSSQLPoolSettings
|
||||
|
||||
instance ToJSON MSSQLPoolSettings where
|
||||
toJSON = genericToJSON hasuraJSON
|
||||
toEncoding = genericToEncoding hasuraJSON
|
||||
deriving via AC.Autodocodec MSSQLPoolSettings instance ToJSON MSSQLPoolSettings
|
||||
|
||||
instance FromJSON MSSQLPoolSettings where
|
||||
parseJSON = withObject "MSSQL pool settings" $ \o ->
|
||||
MSSQLPoolSettings
|
||||
<$> o
|
||||
.:? "max_connections"
|
||||
<*> o
|
||||
.:? "total_max_connections"
|
||||
<*> o
|
||||
.:? "idle_timeout"
|
||||
.!= _mpsIdleTimeout defaultMSSQLPoolSettings
|
||||
deriving via AC.Autodocodec MSSQLPoolSettings instance FromJSON MSSQLPoolSettings
|
||||
|
||||
instance HasCodec MSSQLPoolSettings where
|
||||
codec =
|
||||
AC.object "MSSQLPoolSettings"
|
||||
$ MSSQLPoolSettings
|
||||
<$> optionalFieldWithDefault' "max_connections" (Just defaultMSSQLMaxConnections)
|
||||
AC..= _mpsMaxConnections
|
||||
<*> optionalFieldOrNull' "total_max_connections"
|
||||
AC..= _mpsTotalMaxConnections
|
||||
<*> optionalFieldWithDefault' "idle_timeout" (_mpsIdleTimeout defaultMSSQLPoolSettings)
|
||||
AC..= _mpsIdleTimeout
|
||||
AC.matchChoiceCodec codecNoPool codecWithPool toInput
|
||||
where
|
||||
toInput :: MSSQLPoolSettings -> Either MSSQLPoolSettings MSSQLPoolSettings
|
||||
toInput = \case
|
||||
p@MSSQLPoolSettingsNoPool {} -> Left p
|
||||
p@MSSQLPoolSettings {} -> Right p
|
||||
|
||||
codecNoPool :: AC.JSONCodec MSSQLPoolSettings
|
||||
codecNoPool =
|
||||
AC.bimapCodec
|
||||
( \case
|
||||
False -> Right MSSQLPoolSettingsNoPool
|
||||
True -> Left "impossible, guarded by 'EqCodec False"
|
||||
)
|
||||
( \case
|
||||
MSSQLPoolSettingsNoPool -> False
|
||||
_ -> True
|
||||
)
|
||||
$ AC.EqCodec False
|
||||
$ AC.object "MSSQLPoolSettingsNoPool"
|
||||
$ AC.requiredField "enable" "Whether the connection pool is entirely disabled"
|
||||
|
||||
codecWithPool :: AC.JSONCodec MSSQLPoolSettings
|
||||
codecWithPool =
|
||||
AC.object "MSSQLPoolSettings"
|
||||
$ MSSQLPoolSettings
|
||||
<$> optionalFieldWithDefault' "max_connections" (Just defaultMSSQLMaxConnections)
|
||||
AC..= _mpsMaxConnections
|
||||
<*> optionalFieldOrNull' "total_max_connections"
|
||||
AC..= _mpsTotalMaxConnections
|
||||
<*> optionalFieldWithDefault' "idle_timeout" (_mpsIdleTimeout defaultMSSQLPoolSettings)
|
||||
AC..= _mpsIdleTimeout
|
||||
|
||||
defaultMSSQLMaxConnections :: Int
|
||||
defaultMSSQLMaxConnections = 50
|
||||
|
Loading…
Reference in New Issue
Block a user