Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ All notable changes to this project will be documented in this file. From versio
- Log host, port and pg version of listener database connection by @mkleczek in #4617 #4618
- Optimize requests with `Prefer: count=exact` that do not use ranges or `db-max-rows` by @laurenceisla in #3957
+ Removed unnecessary double count when building the `Content-Range`.
- Expose db pool flushes counter by @mkleczek in #4658

### Changed

Expand Down
10 changes: 10 additions & 0 deletions docs/references/observability.rst
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,16 @@ pgrst_db_pool_timeouts_total

The total number of pool connection timeouts.

pgrst_db_pool_flushes_total
~~~~~~~~~~~~~~~~~~~~~~~~~~~

======== =======
**Type** Counter
======== =======

The total number of times the pool was flushed.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we should mention this means releasing all the connections in the pool, which always happens during schema cache load?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

which always happens during schema cache load?

Hm, actually I'm not sure if the above will be true once #4645 is merged

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

which always happens during schema cache load?

Hm, actually I'm not sure if the above will be true once #4645 is merged

@steve-chavez Added a short sentence to the documentation.

The pool is flushed after successful schema cache reload.

pgrst_db_pool_available
~~~~~~~~~~~~~~~~~~~~~~~

Expand Down
1 change: 1 addition & 0 deletions postgrest.cabal
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,7 @@ test-suite spec
Feature.ConcurrentSpec
Feature.CorsSpec
Feature.ExtraSearchPathSpec
Feature.MetricsSpec
Feature.NoSuperuserSpec
Feature.ObservabilitySpec
Feature.OpenApi.DisabledOpenApiSpec
Expand Down
6 changes: 5 additions & 1 deletion src/PostgREST/AppState.hs
Original file line number Diff line number Diff line change
Expand Up @@ -270,10 +270,14 @@ usePool AppState{stateObserver=observer, stateMainThreadId=mainThreadId, ..} ses

-- | Flush the connection pool so that any future use of the pool will
-- use connections freshly established after this call.
-- | Emits PoolFlushed observation
flushPool :: AppState -> IO ()
flushPool AppState{..} = SQL.release statePool
flushPool AppState{..} = do
SQL.release statePool
stateObserver PoolFlushed

-- | Destroy the pool on shutdown.
-- | Differs from flushPool in not emiting PoolFlushed observation.
destroyPool :: AppState -> IO ()
destroyPool AppState{..} = SQL.release statePool

Expand Down
3 changes: 3 additions & 0 deletions src/PostgREST/Logger.hs
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,9 @@ observationLogger loggerState logLevel obs = case obs of
o@PoolRequestFullfilled ->
when (logLevel >= LogDebug) $ do
logWithZTime loggerState $ observationMessage o
o@PoolFlushed ->
when (logLevel >= LogDebug) $ do
logWithZTime loggerState $ observationMessage o
o@JwtCacheEviction ->
when (logLevel >= LogDebug) $ do
logWithZTime loggerState $ observationMessage o
Expand Down
4 changes: 4 additions & 0 deletions src/PostgREST/Metrics.hs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import Protolude
data MetricsState =
MetricsState {
poolTimeouts :: Counter,
poolFlushes :: Counter,
poolAvailable :: Gauge,
poolWaiting :: Gauge,
poolMaxSize :: Gauge,
Expand All @@ -36,6 +37,7 @@ init :: Int -> IO MetricsState
init configDbPoolSize = do
metricState <- MetricsState <$>
register (counter (Info "pgrst_db_pool_timeouts_total" "The total number of pool connection timeouts")) <*>
register (counter (Info "pgrst_db_pool_flushes_total" "The total number of times the pool was flushed")) <*>
register (gauge (Info "pgrst_db_pool_available" "Available connections in the pool")) <*>
register (gauge (Info "pgrst_db_pool_waiting" "Requests waiting to acquire a pool connection")) <*>
register (gauge (Info "pgrst_db_pool_max" "Max pool connections")) <*>
Expand Down Expand Up @@ -64,6 +66,8 @@ observationMetrics MetricsState{..} obs = case obs of
incGauge poolWaiting
PoolRequestFullfilled ->
decGauge poolWaiting
PoolFlushed ->
incCounter poolFlushes
SchemaCacheLoadedObs resTime -> do
withLabel schemaCacheLoads "SUCCESS" incCounter
setGauge schemaCacheQueryTime resTime
Expand Down
3 changes: 3 additions & 0 deletions src/PostgREST/Observation.hs
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ data Observation
| HasqlPoolObs SQL.Observation
| PoolRequest
| PoolRequestFullfilled
| PoolFlushed
| JwtCacheLookup Bool
| JwtCacheEviction
| WarpErrorObs Text
Expand Down Expand Up @@ -157,6 +158,8 @@ observationMessage = \case
"Trying to borrow a connection from pool"
PoolRequestFullfilled ->
"Borrowed a connection from the pool"
PoolFlushed ->
"Database connection pool flushed"
JwtCacheLookup _ ->
"Looked up a JWT in JWT cache"
JwtCacheEviction ->
Expand Down
48 changes: 48 additions & 0 deletions test/spec/Feature/MetricsSpec.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE TypeApplications #-}
module Feature.MetricsSpec

where

import Network.Wai (Application)

import qualified PostgREST.AppState as AppState
import PostgREST.Metrics (MetricsState (..))
import PostgREST.Observation
import Protolude
import SpecHelper
import System.Timeout (timeout)
import Test.Hspec (SpecWith, describe,
expectationFailure, it)
import Test.Hspec.Wai (getState)

untilM :: Int -> (a -> Bool) -> IO a -> IO (Maybe a)
untilM t cond act = timeout t $ fix $
\loop -> do
value <- act
if cond value then
pure value
else
loop

waitForSchemaReload :: Int -> IO Observation -> IO (Maybe Observation)
waitForSchemaReload t = untilM t $ \case
SchemaCacheLoadedObs _ -> True
_ -> False

spec :: SpecWith ((MetricsState, AppState.AppState, IO Observation), Application)
spec = describe "Server started with metrics enabled" $
it "Should increase pool flushes metric when schema cache is reloaded" $ do
(metrics, appState, readObs) <- getState

checkState' metrics

[
expectCounter @"poolFlushes" (+1)
] $

liftIO $ do
AppState.schemaCacheLoader appState
waitForSchemaReload 1000000 readObs >>=
maybe (expectationFailure "Timeout waiting for schema reloading") mempty
12 changes: 12 additions & 0 deletions test/spec/Main.hs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import qualified Feature.Auth.NoJwtSecretSpec
import qualified Feature.ConcurrentSpec
import qualified Feature.CorsSpec
import qualified Feature.ExtraSearchPathSpec
import qualified Feature.MetricsSpec
import qualified Feature.NoSuperuserSpec
import qualified Feature.ObservabilitySpec
import qualified Feature.OpenApi.DisabledOpenApiSpec
Expand Down Expand Up @@ -87,6 +88,7 @@ main = do
sockets <- AppState.initSockets testCfg
loggerState <- Logger.init
metricsState <- Metrics.init (configDbPoolSize testCfg)
obsChan <- newChan

let
initApp sCache st config = do
Expand All @@ -95,6 +97,12 @@ main = do
AppState.putSchemaCache appState (Just sCache)
return (st, postgrest (configLogLevel config) appState (pure ()))

initMetricsApp sCache config = do
appState <- AppState.initWithPool sockets pool config loggerState metricsState (Metrics.observationMetrics metricsState <> writeChan obsChan)
AppState.putPgVersion appState actualPgVersion
AppState.putSchemaCache appState (Just sCache)
return ((metricsState, appState, readChan obsChan), postgrest (configLogLevel config) appState (pure ()))

-- For tests that run with the same schema cache
app = initApp baseSchemaCache ()

Expand Down Expand Up @@ -123,6 +131,7 @@ main = do
obsApp = app testObservabilityCfg
serverTiming = app testCfgServerTiming
aggregatesEnabled = app testCfgAggregatesEnabled
metricsApp = initMetricsApp baseSchemaCache testCfg

extraSearchPathApp = appDbs testCfgExtraSearchPath
unicodeApp = appDbs testUnicodeCfg
Expand Down Expand Up @@ -278,6 +287,9 @@ main = do
before (initApp baseSchemaCache metricsState testCfgJwtCache) $
describe "Feature.Auth.JwtCacheSpec" Feature.Auth.JwtCacheSpec.spec

before metricsApp $
describe "Feature.MetricsSpec" Feature.MetricsSpec.spec

where
loadSCache pool conf =
either (panic.show) id <$> P.use pool (HT.transaction HT.ReadCommitted HT.Read $ querySchemaCache conf)