@@ -33,8 +33,6 @@ module PostgREST.AppState
3333import qualified Data.ByteString.Char8 as BS
3434import Data.Either.Combinators (whenLeft )
3535import qualified Data.Text as T (unpack )
36- import qualified Hasql.Pool as SQL
37- import qualified Hasql.Pool.Config as SQL
3836import qualified Hasql.Session as SQL
3937import qualified Hasql.Transaction.Sessions as SQL
4038import qualified Network.HTTP.Types.Status as HTTP
@@ -74,11 +72,14 @@ import PostgREST.Unix (createAndBindDomainSocket)
7472
7573import Data.Streaming.Network (bindPortTCP , bindRandomPortTCP )
7674import Data.String (IsString (.. ))
75+ import qualified Hasql.Connection as SQL
76+ import qualified PostgREST.SemPool as Sem
7777import Protolude
78+ import Hasql.Pool (UsageError (.. ))
7879
7980data AppState = AppState
8081 -- | Database connection pool
81- { statePool :: SQL . Pool
82+ { statePool :: Sem . Pool SQL. ConnectionError SQL. Connection
8283 -- | Database server version
8384 , statePgVersion :: IORef PgVersion
8485 -- | Schema cache
@@ -132,7 +133,7 @@ init conf@AppConfig{configLogLevel, configDbPoolSize} = do
132133 state' <- initWithPool (sock, adminSock) pool conf loggerState metricsState observer
133134 pure state' { stateSocketREST = sock, stateSocketAdmin = adminSock}
134135
135- initWithPool :: AppSockets -> SQL . Pool -> AppConfig -> Logger. LoggerState -> Metrics. MetricsState -> ObservationHandler -> IO AppState
136+ initWithPool :: AppSockets -> Sem . Pool SQL. ConnectionError SQL. Connection -> AppConfig -> Logger. LoggerState -> Metrics. MetricsState -> ObservationHandler -> IO AppState
136137initWithPool (sock, adminSock) pool conf loggerState metricsState observer = do
137138
138139 appState <- AppState pool
@@ -200,35 +201,40 @@ initSockets AppConfig{..} = do
200201
201202 pure (sock, adminSock)
202203
203- initPool :: AppConfig -> ObservationHandler -> IO SQL. Pool
204- initPool AppConfig {.. } observer = do
205- SQL. acquire $ SQL. settings
206- [ SQL. size configDbPoolSize
207- , SQL. acquisitionTimeout $ fromIntegral configDbPoolAcquisitionTimeout
208- , SQL. agingTimeout $ fromIntegral configDbPoolMaxLifetime
209- , SQL. idlenessTimeout $ fromIntegral configDbPoolMaxIdletime
210- , SQL. staticConnectionSettings (toUtf8 $ addFallbackAppName prettyVersion configDbUri)
211- , SQL. observationHandler $ observer . HasqlPoolObs
212- ]
204+ initPool :: AppConfig -> ObservationHandler -> IO (Sem. Pool SQL. ConnectionError SQL. Connection )
205+ initPool AppConfig {.. } _ = do
206+ Sem. pool configDbPoolSize configDbPoolAcquisitionTimeout (SQL. acquire (toUtf8 $ addFallbackAppName prettyVersion configDbUri)) (const $ pure mempty ) SQL. release
207+ -- where
208+ -- settings =
209+ -- SQL.settings
210+ -- [ SQL.size configDbPoolSize
211+ -- , SQL.acquisitionTimeout $ fromIntegral configDbPoolAcquisitionTimeout
212+ -- , SQL.agingTimeout $ fromIntegral configDbPoolMaxLifetime
213+ -- , SQL.idlenessTimeout $ fromIntegral configDbPoolMaxIdletime
214+ -- , SQL.staticConnectionSettings (toUtf8 $ addFallbackAppName prettyVersion configDbUri)
215+ -- , SQL.observationHandler $ observer . HasqlPoolObs
216+ -- ]
213217
214218-- | Run an action with a database connection.
215- usePool :: AppState -> SQL. Session a -> IO (Either SQL. UsageError a )
219+ usePool :: AppState -> SQL. Session a -> IO (Either UsageError a )
216220usePool AppState {stateObserver= observer, stateMainThreadId= mainThreadId, .. } sess = do
217221 observer PoolRequest
218222
219- res <- SQL. use statePool sess
223+ res <- join . first (\ case
224+ Sem. AcquireTimeout -> AcquisitionTimeoutUsageError
225+ (Sem. ResourceError e) -> ConnectionUsageError e) <$> Sem. use statePool (fmap (first SessionUsageError ) . SQL. run sess)
220226
221227 observer PoolRequestFullfilled
222228
223229 whenLeft res (\ case
224- SQL. AcquisitionTimeoutUsageError ->
225- observer $ PoolAcqTimeoutObs SQL. AcquisitionTimeoutUsageError
226- err@ (SQL. ConnectionUsageError e) ->
230+ AcquisitionTimeoutUsageError ->
231+ observer $ PoolAcqTimeoutObs AcquisitionTimeoutUsageError
232+ err@ (ConnectionUsageError e) ->
227233 let failureMessage = BS. unpack $ fromMaybe mempty e in
228234 when ((" FATAL: password authentication failed" `isInfixOf` failureMessage) || (" no password supplied" `isInfixOf` failureMessage)) $ do
229235 observer $ ExitDBFatalError ServerAuthError err
230236 killThread mainThreadId
231- err@ (SQL. SessionUsageError (SQL. QueryError tpl _ (SQL. ResultError resultErr))) -> do
237+ err@ (SessionUsageError (SQL. QueryError tpl _ (SQL. ResultError resultErr))) -> do
232238 case resultErr of
233239 SQL. UnexpectedResult {} -> do
234240 observer $ ExitDBFatalError ServerPgrstBug err
@@ -261,7 +267,7 @@ usePool AppState{stateObserver=observer, stateMainThreadId=mainThreadId, ..} ses
261267 SQL. ServerError {} ->
262268 when (Error. status (Error. PgError False err) >= HTTP. status500) $
263269 observer $ QueryErrorCodeHighObs err
264- err@ (SQL. SessionUsageError (SQL. QueryError _ _ (SQL. ClientError _))) ->
270+ err@ (SessionUsageError (SQL. QueryError _ _ (SQL. ClientError _))) ->
265271 -- An error on the client-side, usually indicates problems wth connection
266272 observer $ QueryErrorCodeHighObs err
267273 )
@@ -271,11 +277,11 @@ usePool AppState{stateObserver=observer, stateMainThreadId=mainThreadId, ..} ses
271277-- | Flush the connection pool so that any future use of the pool will
272278-- use connections freshly established after this call.
273279flushPool :: AppState -> IO ()
274- flushPool AppState {.. } = SQL . release statePool
280+ flushPool AppState {.. } = Sem . release statePool
275281
276282-- | Destroy the pool on shutdown.
277283destroyPool :: AppState -> IO ()
278- destroyPool AppState {.. } = SQL . release statePool
284+ destroyPool AppState {.. } = Sem . release statePool
279285
280286getPgVersion :: AppState -> IO PgVersion
281287getPgVersion = readIORef . statePgVersion
0 commit comments