perf: skip favouriteQuickActions under db conn pressure

This commit is contained in:
Gregor Kleen 2021-03-08 12:55:48 +01:00
parent 63f0d3c37a
commit 55a9c8a5ae
5 changed files with 42 additions and 13 deletions

View File

@ -1,6 +1,7 @@
module Foundation.DB module Foundation.DB
( runDBRead, runDBRead' ( runDBRead, runDBRead'
, runSqlPoolRetry, runSqlPoolRetry' , runSqlPoolRetry, runSqlPoolRetry'
, dbPoolPressured
) where ) where
import Import.NoFoundation hiding (runDB, getDBRunner) import Import.NoFoundation hiding (runDB, getDBRunner)
@ -61,3 +62,13 @@ runDBRead' :: CallStack -> ReaderT SqlReadBackend (HandlerFor UniWorX) a -> (Han
runDBRead' lbl action = do runDBRead' lbl action = do
$logDebugS "YesodPersist" "runDBRead" $logDebugS "YesodPersist" "runDBRead"
flip (runSqlPoolRetry' . withReaderT SqlReadBackend $ [executeQQ|SET TRANSACTION READ ONLY|] *> action) lbl . appConnPool =<< getYesod flip (runSqlPoolRetry' . withReaderT SqlReadBackend $ [executeQQ|SET TRANSACTION READ ONLY|] *> action) lbl . appConnPool =<< getYesod
dbPoolPressured :: ( MonadHandler m
, HandlerSite m ~ UniWorX
)
=> m Bool
dbPoolPressured = do
connPool <- getsYesod @_ @(Custom.Pool' IO _ _ _) appConnPool
case Custom.getPoolMaxAvailable connPool of
Nothing -> return False
Just lim -> atomically $ (>= lim) <$> Custom.getPoolInUseCount connPool

View File

@ -191,18 +191,21 @@ siteLayout' overrideHeading widget = do
langs <- selectLanguages appLanguages <$> languages langs <- selectLanguages appLanguages <$> languages
let cK = MemcachedKeyFavouriteQuickActions (tid, ssh, csh) ctx langs let cK = MemcachedKeyFavouriteQuickActions (tid, ssh, csh) ctx langs
$logDebugS "FavouriteQuickActions" $ tshow cK <> " Checking..." $logDebugS "FavouriteQuickActions" $ tshow cK <> " Checking..."
items <- memcachedLimitedKeyTimeoutBy poolIsPressured <- dbPoolPressured
MemcachedLimitKeyFavourites appFavouritesQuickActionsBurstsize appFavouritesQuickActionsAvgInverseRate 1 items <- if
(Right <$> appFavouritesQuickActionsCacheTTL) | poolIsPressured -> Nothing <$ observeFavouritesSkippedDueToDBLoad
appFavouritesQuickActionsTimeout | otherwise -> memcachedLimitedKeyTimeoutBy
cK MemcachedLimitKeyFavourites appFavouritesQuickActionsBurstsize appFavouritesQuickActionsAvgInverseRate 1
cK (Right <$> appFavouritesQuickActionsCacheTTL)
. observeFavouritesQuickActionsDuration $ do appFavouritesQuickActionsTimeout
$logDebugS "FavouriteQuickActions" $ tshow cK <> " Starting..." cK
items' <- pageQuickActions NavQuickViewFavourite courseRoute cK
items <- forM items' $ \n@NavLink{navLabel} -> fmap (mr navLabel,) $ toTextUrl =<< navLinkRoute n . observeFavouritesQuickActionsDuration $ do
$logDebugS "FavouriteQuickActions" $ tshow cK <> " Done." $logDebugS "FavouriteQuickActions" $ tshow cK <> " Starting..."
return items items' <- pageQuickActions NavQuickViewFavourite courseRoute
items <- forM items' $ \n@NavLink{navLabel} -> fmap (mr navLabel,) $ toTextUrl =<< navLinkRoute n
$logDebugS "FavouriteQuickActions" $ tshow cK <> " Done."
return items
$logDebugS "FavouriteQuickActions" $ tshow cK <> " returning " <> tshow (is _Just items) $logDebugS "FavouriteQuickActions" $ tshow cK <> " returning " <> tshow (is _Just items)
return (c, courseRoute, items, favouriteReason, courseVisible, mayView, mayEdit) return (c, courseRoute, items, favouriteReason, courseVisible, mayView, mayEdit)

View File

@ -11,7 +11,6 @@ import Data.Map as Map
-- import Data.CaseInsensitive (CI) -- import Data.CaseInsensitive (CI)
-- import qualified Data.CaseInsensitive as CI -- import qualified Data.CaseInsensitive as CI
import qualified Database.Esqueleto as E import qualified Database.Esqueleto as E
makeSchoolDictionaryDB :: DB (Map.Map SchoolId SchoolName) makeSchoolDictionaryDB :: DB (Map.Map SchoolId SchoolName)

View File

@ -25,6 +25,7 @@ module Utils.Metrics
, observeDatabaseConnectionOpened, observeDatabaseConnectionClosed , observeDatabaseConnectionOpened, observeDatabaseConnectionClosed
, onUseDBConn, onReleaseDBConn, DBConnUseState, DBConnLabel , onUseDBConn, onReleaseDBConn, DBConnUseState, DBConnLabel
, AuthTagEvalOutcome(..), observeAuthTagEvaluation , AuthTagEvalOutcome(..), observeAuthTagEvaluation
, observeFavouritesSkippedDueToDBLoad
) where ) where
import Import.NoModel hiding (Vector, Info) import Import.NoModel hiding (Vector, Info)
@ -259,6 +260,12 @@ missingFiles = unsafeRegister . vector "ref" $ gauge info
where info = Info "uni2work_missing_files_count" where info = Info "uni2work_missing_files_count"
"Number of files referenced from within database that are missing" "Number of files referenced from within database that are missing"
{-# NOINLINE favouritesSkippedDueToDBLoad #-}
favouritesSkippedDueToDBLoad :: Counter
favouritesSkippedDueToDBLoad = unsafeRegister $ counter info
where info = Info "uni2work_favourites_skipped_due_to_db_load_count"
"Number of times this Uni2work-instance skipped generating FavouriteQuickActions due to database pressure"
relabel :: Text -> Text relabel :: Text -> Text
-> SampleGroup -> SampleGroup -> SampleGroup -> SampleGroup
relabel l s (SampleGroup i t ss) = SampleGroup i t . flip map ss $ \(Sample k lbls v) -> Sample k ((l, s) : filter (views _1 $ (/=) l) lbls) v relabel l s (SampleGroup i t ss) = SampleGroup i t . flip map ss $ \(Sample k lbls v) -> Sample k ((l, s) : filter (views _1 $ (/=) l) lbls) v
@ -592,3 +599,6 @@ observeAuthTagEvaluation aTag act = do
liftIO . withLabel authTagEvaluationDuration (toPathPiece aTag, toPathPiece outcome) . flip observe . realToFrac $ end - start liftIO . withLabel authTagEvaluationDuration (toPathPiece aTag, toPathPiece outcome) . flip observe . realToFrac $ end - start
either throwIO (views _1 return) res either throwIO (views _1 return) res
observeFavouritesSkippedDueToDBLoad :: MonadIO m => m ()
observeFavouritesSkippedDueToDBLoad = liftIO $ incCounter favouritesSkippedDueToDBLoad

View File

@ -5,6 +5,7 @@ module Utils.Pool
, PoolResourceIdent' , PoolResourceIdent'
, Pool, PoolResourceIdent , Pool, PoolResourceIdent
, getPoolAvailableCount, getPoolInUseCount, getPoolUsesCount , getPoolAvailableCount, getPoolInUseCount, getPoolUsesCount
, getPoolIdleTime, getPoolMaxAvailable
, createPool, createPool' , createPool, createPool'
, purgePool , purgePool
, withResource, withResource' , withResource, withResource'
@ -24,6 +25,7 @@ import UnliftIO.Concurrent (forkIO)
import Data.Fixed import Data.Fixed
import System.Clock import System.Clock
import Data.Time.Clock (DiffTime)
import Control.Concurrent.STM.Delay import Control.Concurrent.STM.Delay
import Control.Concurrent.STM.TVar (stateTVar) import Control.Concurrent.STM.TVar (stateTVar)
@ -78,6 +80,10 @@ getPoolAvailableCount Pool{..} = availableCount <$> readTVar resources
getPoolInUseCount Pool{..} = inUseCount <$> readTVar resources getPoolInUseCount Pool{..} = inUseCount <$> readTVar resources
getPoolUsesCount Pool{..} = inUseTick <$> readTVar resources getPoolUsesCount Pool{..} = inUseTick <$> readTVar resources
getPoolIdleTime :: Pool' m c' c a -> Maybe DiffTime
getPoolIdleTime = fmap realToFrac . maxAvailable
getPoolMaxAvailable :: Pool' m c' c a -> Maybe Int
getPoolMaxAvailable = maxAvailable
toSecond :: TimeSpec -> Int toSecond :: TimeSpec -> Int
toSecond = fromIntegral . sec toSecond = fromIntegral . sec