feat: improve logging/metrics wrt. batch jobs
This commit is contained in:
parent
8afacdd6b7
commit
d21faf4de0
@ -102,6 +102,7 @@ handleJobs foundation@UniWorX{..}
|
|||||||
jobCurrentCrontab <- liftIO $ newTVarIO Nothing
|
jobCurrentCrontab <- liftIO $ newTVarIO Nothing
|
||||||
jobHeldLocks <- liftIO $ newTVarIO Set.empty
|
jobHeldLocks <- liftIO $ newTVarIO Set.empty
|
||||||
registerJobHeldLocksCount jobHeldLocks
|
registerJobHeldLocksCount jobHeldLocks
|
||||||
|
registerJobWorkerQueueDepth appJobState
|
||||||
atomically $ putTMVar appJobState JobState
|
atomically $ putTMVar appJobState JobState
|
||||||
{ jobContext = JobContext{..}
|
{ jobContext = JobContext{..}
|
||||||
, ..
|
, ..
|
||||||
@ -452,6 +453,12 @@ handleJobs' wNum = C.mapM_ $ \jctl -> hoist delimitInternalState . withJobWorker
|
|||||||
JobHandlerException act -> do
|
JobHandlerException act -> do
|
||||||
act & withJobWorkerState wNum (JobWorkerExecJob content)
|
act & withJobWorkerState wNum (JobWorkerExecJob content)
|
||||||
runDB $ setSerializable cleanup
|
runDB $ setSerializable cleanup
|
||||||
|
JobHandlerAtomicWithFinalizer act fin -> do
|
||||||
|
res <- runDBJobs . setSerializable $ do
|
||||||
|
res <- act & withJobWorkerState wNum (JobWorkerExecJob content)
|
||||||
|
hoist lift cleanup
|
||||||
|
return res
|
||||||
|
fin res
|
||||||
handleCmd JobCtlDetermineCrontab = do
|
handleCmd JobCtlDetermineCrontab = do
|
||||||
newCTab <- liftHandler . runDB $ setSerializable determineCrontab'
|
newCTab <- liftHandler . runDB $ setSerializable determineCrontab'
|
||||||
-- logDebugS logIdent $ tshow newCTab
|
-- logDebugS logIdent $ tshow newCTab
|
||||||
|
|||||||
@ -34,11 +34,13 @@ import Handler.Utils.Files (sourceFileDB)
|
|||||||
|
|
||||||
|
|
||||||
dispatchJobPruneSessionFiles :: JobHandler UniWorX
|
dispatchJobPruneSessionFiles :: JobHandler UniWorX
|
||||||
dispatchJobPruneSessionFiles = JobHandlerAtomic . hoist lift $ do
|
dispatchJobPruneSessionFiles = JobHandlerAtomicWithFinalizer act fin
|
||||||
now <- liftIO getCurrentTime
|
where
|
||||||
expires <- getsYesod $ view _appSessionFilesExpire
|
act = hoist lift $ do
|
||||||
n <- deleteWhereCount [ SessionFileTouched <. addUTCTime (- expires) now ]
|
now <- liftIO getCurrentTime
|
||||||
$logInfoS "PruneSessionFiles" [st|Deleted #{n} expired session files|]
|
expires <- getsYesod $ view _appSessionFilesExpire
|
||||||
|
deleteWhereCount [ SessionFileTouched <. addUTCTime (- expires) now ]
|
||||||
|
fin n = $logInfoS "PruneSessionFiles" [st|Deleted #{n} expired session files|]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -64,142 +66,146 @@ pruneUnreferencedFilesIntervalsCache :: TVar (Map Natural [(Maybe FileContentChu
|
|||||||
pruneUnreferencedFilesIntervalsCache = unsafePerformIO $ newTVarIO Map.empty
|
pruneUnreferencedFilesIntervalsCache = unsafePerformIO $ newTVarIO Map.empty
|
||||||
|
|
||||||
dispatchJobPruneUnreferencedFiles :: Natural -> Natural -> Natural -> JobHandler UniWorX
|
dispatchJobPruneUnreferencedFiles :: Natural -> Natural -> Natural -> JobHandler UniWorX
|
||||||
dispatchJobPruneUnreferencedFiles numIterations epoch iteration = JobHandlerAtomic . hoist lift $ do
|
dispatchJobPruneUnreferencedFiles numIterations epoch iteration = JobHandlerAtomicWithFinalizer act fin
|
||||||
now <- liftIO getCurrentTime
|
where
|
||||||
interval <- getsYesod $ view _appPruneUnreferencedFilesInterval
|
act = hoist lift $ do
|
||||||
keep <- fmap (max 0) . getsYesod $ view _appKeepUnreferencedFiles
|
now <- liftIO getCurrentTime
|
||||||
|
interval <- getsYesod $ view _appPruneUnreferencedFilesInterval
|
||||||
|
keep <- fmap (max 0) . getsYesod $ view _appKeepUnreferencedFiles
|
||||||
|
|
||||||
let
|
let
|
||||||
chunkHashBytes :: forall h.
|
chunkHashBytes :: forall h.
|
||||||
( Unwrapped FileContentChunkReference ~ Digest h )
|
( Unwrapped FileContentChunkReference ~ Digest h )
|
||||||
=> Integer
|
=> Integer
|
||||||
chunkHashBytes = fromIntegral (hashDigestSize (error "hashDigestSize inspected argument" :: h))
|
chunkHashBytes = fromIntegral (hashDigestSize (error "hashDigestSize inspected argument" :: h))
|
||||||
chunkHashBits = chunkHashBytes * 8
|
chunkHashBits = chunkHashBytes * 8
|
||||||
base :: Integer
|
base :: Integer
|
||||||
base = 2 ^ chunkHashBits
|
base = 2 ^ chunkHashBits
|
||||||
intervals :: [Integer]
|
intervals :: [Integer]
|
||||||
-- | Exclusive upper bounds
|
|
||||||
intervals
|
|
||||||
| numIterations <= 0 = pure base
|
|
||||||
| otherwise = go protoIntervals ^.. folded . _1
|
|
||||||
where
|
|
||||||
go [] = []
|
|
||||||
go ints
|
|
||||||
| maximumOf (folded . _1) ints == Just base = ints
|
|
||||||
| otherwise = go $ lts ++ over _1 succ (over _2 (subtract $ toInteger numIterations) closest) : map (over _1 succ) gts
|
|
||||||
where
|
|
||||||
closest = maximumBy (comparing $ view _2) ints
|
|
||||||
(lts, geqs) = partition (((>) `on` view _1) closest) ints
|
|
||||||
gts = filter (((<) `on` view _1) closest) geqs
|
|
||||||
-- | Exclusive upper bounds
|
-- | Exclusive upper bounds
|
||||||
protoIntervals :: [(Integer, Integer)]
|
intervals
|
||||||
protoIntervals = [ over _1 (i *) $ base `divMod` toInteger numIterations
|
| numIterations <= 0 = pure base
|
||||||
| i <- [1 .. toInteger numIterations]
|
| otherwise = go protoIntervals ^.. folded . _1
|
||||||
]
|
where
|
||||||
|
go [] = []
|
||||||
|
go ints
|
||||||
|
| maximumOf (folded . _1) ints == Just base = ints
|
||||||
|
| otherwise = go $ lts ++ over _1 succ (over _2 (subtract $ toInteger numIterations) closest) : map (over _1 succ) gts
|
||||||
|
where
|
||||||
|
closest = maximumBy (comparing $ view _2) ints
|
||||||
|
(lts, geqs) = partition (((>) `on` view _1) closest) ints
|
||||||
|
gts = filter (((<) `on` view _1) closest) geqs
|
||||||
|
-- | Exclusive upper bounds
|
||||||
|
protoIntervals :: [(Integer, Integer)]
|
||||||
|
protoIntervals = [ over _1 (i *) $ base `divMod` toInteger numIterations
|
||||||
|
| i <- [1 .. toInteger numIterations]
|
||||||
|
]
|
||||||
|
|
||||||
intervalsDgsts' = zipWith (curry . over both $ toDigest <=< assertM' (> 0)) (0 : init intervals) intervals
|
intervalsDgsts' = zipWith (curry . over both $ toDigest <=< assertM' (> 0)) (0 : init intervals) intervals
|
||||||
|
|
||||||
toDigest :: Integer -> Maybe FileContentChunkReference
|
toDigest :: Integer -> Maybe FileContentChunkReference
|
||||||
toDigest = fmap (review _Wrapped) . digestFromByteString . pad . ByteString.pack . reverse . unfoldr step
|
toDigest = fmap (review _Wrapped) . digestFromByteString . pad . ByteString.pack . reverse . unfoldr step
|
||||||
where step i
|
where step i
|
||||||
| i <= 0 = Nothing
|
| i <= 0 = Nothing
|
||||||
| otherwise = Just (fromIntegral i, i `shiftR` 8)
|
| otherwise = Just (fromIntegral i, i `shiftR` 8)
|
||||||
pad bs
|
pad bs
|
||||||
| toInteger (ByteString.length bs) >= chunkHashBytes = bs
|
| toInteger (ByteString.length bs) >= chunkHashBytes = bs
|
||||||
| otherwise = pad $ ByteString.cons 0 bs
|
| otherwise = pad $ ByteString.cons 0 bs
|
||||||
|
|
||||||
intervalsDgsts <- atomically $ do
|
intervalsDgsts <- atomically $ do
|
||||||
cachedDgsts <- readTVar pruneUnreferencedFilesIntervalsCache
|
cachedDgsts <- readTVar pruneUnreferencedFilesIntervalsCache
|
||||||
case Map.lookup numIterations cachedDgsts of
|
case Map.lookup numIterations cachedDgsts of
|
||||||
Just c -> return c
|
Just c -> return c
|
||||||
Nothing -> do
|
Nothing -> do
|
||||||
modifyTVar' pruneUnreferencedFilesIntervalsCache $ force . Map.insert numIterations intervalsDgsts'
|
modifyTVar' pruneUnreferencedFilesIntervalsCache $ force . Map.insert numIterations intervalsDgsts'
|
||||||
return intervalsDgsts'
|
return intervalsDgsts'
|
||||||
|
|
||||||
let
|
let
|
||||||
permIntervalsDgsts = shuffleM intervalsDgsts `evalRand` mkStdGen (hash epoch)
|
permIntervalsDgsts = shuffleM intervalsDgsts `evalRand` mkStdGen (hash epoch)
|
||||||
|
|
||||||
(minBoundDgst, maxBoundDgst) = permIntervalsDgsts !! fromIntegral (toInteger iteration `mod` genericLength permIntervalsDgsts)
|
(minBoundDgst, maxBoundDgst) = permIntervalsDgsts !! fromIntegral (toInteger iteration `mod` genericLength permIntervalsDgsts)
|
||||||
chunkIdFilter :: E.SqlExpr (E.Value FileContentChunkReference) -> E.SqlExpr (E.Value Bool)
|
chunkIdFilter :: E.SqlExpr (E.Value FileContentChunkReference) -> E.SqlExpr (E.Value Bool)
|
||||||
chunkIdFilter cRef = E.and $ catMaybes
|
chunkIdFilter cRef = E.and $ catMaybes
|
||||||
[ minBoundDgst <&> \b -> cRef E.>=. E.val b
|
[ minBoundDgst <&> \b -> cRef E.>=. E.val b
|
||||||
, maxBoundDgst <&> \b -> cRef E.<. E.val b
|
, maxBoundDgst <&> \b -> cRef E.<. E.val b
|
||||||
]
|
]
|
||||||
|
|
||||||
$logDebugS "PruneUnreferencedFiles" . tshow $ (minBoundDgst, maxBoundDgst)
|
$logDebugS "PruneUnreferencedFiles" . tshow $ (minBoundDgst, maxBoundDgst)
|
||||||
|
|
||||||
E.insertSelectWithConflict
|
E.insertSelectWithConflict
|
||||||
(UniqueFileContentChunkUnreferenced $ error "insertSelectWithConflict inspected constraint")
|
(UniqueFileContentChunkUnreferenced $ error "insertSelectWithConflict inspected constraint")
|
||||||
(E.from $ \fileContentChunk -> do
|
(E.from $ \fileContentChunk -> do
|
||||||
E.where_ . E.not_ . E.subSelectOr . E.from $ \fileContentEntry -> do
|
E.where_ . E.not_ . E.subSelectOr . E.from $ \fileContentEntry -> do
|
||||||
E.where_ $ fileContentEntry E.^. FileContentEntryChunkHash E.==. fileContentChunk E.^. FileContentChunkId
|
E.where_ $ fileContentEntry E.^. FileContentEntryChunkHash E.==. fileContentChunk E.^. FileContentChunkId
|
||||||
|
return . E.any E.exists . fileReferences $ fileContentEntry E.^. FileContentEntryHash
|
||||||
|
E.where_ . chunkIdFilter $ fileContentChunk E.^. FileContentChunkHash
|
||||||
|
return $ FileContentChunkUnreferenced E.<# (fileContentChunk E.^. FileContentChunkId) E.<&> E.val now
|
||||||
|
)
|
||||||
|
(\current excluded ->
|
||||||
|
[ FileContentChunkUnreferencedSince E.=. E.min (current E.^. FileContentChunkUnreferencedSince) (excluded E.^. FileContentChunkUnreferencedSince) ]
|
||||||
|
)
|
||||||
|
|
||||||
|
E.delete . E.from $ \fileContentChunkUnreferenced -> do
|
||||||
|
E.where_ . E.subSelectOr . E.from $ \fileContentEntry -> do
|
||||||
|
E.where_ $ fileContentEntry E.^. FileContentEntryChunkHash E.==. fileContentChunkUnreferenced E.^. FileContentChunkUnreferencedHash
|
||||||
return . E.any E.exists . fileReferences $ fileContentEntry E.^. FileContentEntryHash
|
return . E.any E.exists . fileReferences $ fileContentEntry E.^. FileContentEntryHash
|
||||||
E.where_ . chunkIdFilter $ fileContentChunk E.^. FileContentChunkHash
|
E.where_ . chunkIdFilter $ E.subSelectForeign fileContentChunkUnreferenced FileContentChunkUnreferencedHash (E.^. FileContentChunkHash)
|
||||||
return $ FileContentChunkUnreferenced E.<# (fileContentChunk E.^. FileContentChunkId) E.<&> E.val now
|
|
||||||
)
|
|
||||||
(\current excluded ->
|
|
||||||
[ FileContentChunkUnreferencedSince E.=. E.min (current E.^. FileContentChunkUnreferencedSince) (excluded E.^. FileContentChunkUnreferencedSince) ]
|
|
||||||
)
|
|
||||||
|
|
||||||
E.delete . E.from $ \fileContentChunkUnreferenced -> do
|
let
|
||||||
E.where_ . E.subSelectOr . E.from $ \fileContentEntry -> do
|
getEntryCandidates = E.selectSource . E.from $ \fileContentEntry -> do
|
||||||
E.where_ $ fileContentEntry E.^. FileContentEntryChunkHash E.==. fileContentChunkUnreferenced E.^. FileContentChunkUnreferencedHash
|
let unreferencedSince = E.subSelectMaybe . E.from $ \(fileContentEntry' `E.InnerJoin` fileContentChunkUnreferenced) -> do
|
||||||
return . E.any E.exists . fileReferences $ fileContentEntry E.^. FileContentEntryHash
|
E.on $ fileContentEntry' E.^. FileContentEntryChunkHash E.==. fileContentChunkUnreferenced E.^. FileContentChunkUnreferencedHash
|
||||||
E.where_ . chunkIdFilter $ E.subSelectForeign fileContentChunkUnreferenced FileContentChunkUnreferencedHash (E.^. FileContentChunkHash)
|
E.where_ $ fileContentEntry' E.^. FileContentEntryHash E.==. fileContentEntry E.^. FileContentEntryHash
|
||||||
|
E.where_ . chunkIdFilter $ E.subSelectForeign fileContentChunkUnreferenced FileContentChunkUnreferencedHash (E.^. FileContentChunkHash)
|
||||||
|
return . E.max_ $ fileContentChunkUnreferenced E.^. FileContentChunkUnreferencedSince
|
||||||
|
E.where_ $ E.maybe E.false (E.<. E.val (addUTCTime (-keep) now)) unreferencedSince
|
||||||
|
|
||||||
let
|
E.groupBy $ fileContentEntry E.^. FileContentEntryHash
|
||||||
getEntryCandidates = E.selectSource . E.from $ \fileContentEntry -> do
|
E.orderBy [ E.asc $ fileContentEntry E.^. FileContentEntryHash ]
|
||||||
let unreferencedSince = E.subSelectMaybe . E.from $ \(fileContentEntry' `E.InnerJoin` fileContentChunkUnreferenced) -> do
|
|
||||||
E.on $ fileContentEntry' E.^. FileContentEntryChunkHash E.==. fileContentChunkUnreferenced E.^. FileContentChunkUnreferencedHash
|
|
||||||
E.where_ $ fileContentEntry' E.^. FileContentEntryHash E.==. fileContentEntry E.^. FileContentEntryHash
|
|
||||||
E.where_ . chunkIdFilter $ E.subSelectForeign fileContentChunkUnreferenced FileContentChunkUnreferencedHash (E.^. FileContentChunkHash)
|
|
||||||
return . E.max_ $ fileContentChunkUnreferenced E.^. FileContentChunkUnreferencedSince
|
|
||||||
E.where_ $ E.maybe E.false (E.<. E.val (addUTCTime (-keep) now)) unreferencedSince
|
|
||||||
|
|
||||||
E.groupBy $ fileContentEntry E.^. FileContentEntryHash
|
return $ fileContentEntry E.^. FileContentEntryHash
|
||||||
E.orderBy [ E.asc $ fileContentEntry E.^. FileContentEntryHash ]
|
|
||||||
|
|
||||||
return $ fileContentEntry E.^. FileContentEntryHash
|
deleteEntry :: _ -> DB (Sum Natural)
|
||||||
|
deleteEntry (E.Value fRef) =
|
||||||
|
bool 0 1 . (> 0) <$> deleteWhereCount [FileContentEntryHash ==. fRef]
|
||||||
|
|
||||||
deleteEntry :: _ -> DB (Sum Natural)
|
Sum deletedEntries <- runConduit $
|
||||||
deleteEntry (E.Value fRef) =
|
getEntryCandidates
|
||||||
bool 0 1 . (> 0) <$> deleteWhereCount [FileContentEntryHash ==. fRef]
|
.| takeWhileTime (interval / 3)
|
||||||
|
.| C.mapM deleteEntry
|
||||||
|
.| C.fold
|
||||||
|
|
||||||
Sum deletedEntries <- runConduit $
|
let
|
||||||
getEntryCandidates
|
getChunkCandidates = E.selectSource . E.from $ \fileContentChunkUnreferenced -> do
|
||||||
.| takeWhileTime (interval / 3)
|
E.where_ $ fileContentChunkUnreferenced E.^. FileContentChunkUnreferencedSince E.<. E.val (addUTCTime (-keep) now)
|
||||||
.| C.mapM deleteEntry
|
E.where_ . E.not_ . E.exists . E.from $ \fileContentEntry ->
|
||||||
.| C.fold
|
E.where_ $ fileContentEntry E.^. FileContentEntryChunkHash E.==. fileContentChunkUnreferenced E.^. FileContentChunkUnreferencedHash
|
||||||
|
|
||||||
when (deletedEntries > 0) $
|
E.where_ . chunkIdFilter $ E.subSelectForeign fileContentChunkUnreferenced FileContentChunkUnreferencedHash (E.^. FileContentChunkHash)
|
||||||
$logInfoS "PruneUnreferencedFiles" [st|Deleted #{tshow deletedEntries} long-unreferenced files|]
|
|
||||||
|
|
||||||
let
|
return ( fileContentChunkUnreferenced E.^. FileContentChunkUnreferencedHash
|
||||||
getChunkCandidates = E.selectSource . E.from $ \fileContentChunkUnreferenced -> do
|
, E.subSelectForeign fileContentChunkUnreferenced FileContentChunkUnreferencedHash $ E.length_ . (E.^. FileContentChunkContent)
|
||||||
E.where_ $ fileContentChunkUnreferenced E.^. FileContentChunkUnreferencedSince E.<. E.val (addUTCTime (-keep) now)
|
)
|
||||||
E.where_ . E.not_ . E.exists . E.from $ \fileContentEntry ->
|
|
||||||
E.where_ $ fileContentEntry E.^. FileContentEntryChunkHash E.==. fileContentChunkUnreferenced E.^. FileContentChunkUnreferencedHash
|
|
||||||
|
|
||||||
E.where_ . chunkIdFilter $ E.subSelectForeign fileContentChunkUnreferenced FileContentChunkUnreferencedHash (E.^. FileContentChunkHash)
|
deleteChunk :: _ -> DB (Sum Natural, Sum Word64)
|
||||||
|
deleteChunk (E.Value cRef, E.Value size) = do
|
||||||
|
deleteWhere [ FileContentChunkUnreferencedHash ==. cRef ]
|
||||||
|
(, Sum size) . fromIntegral <$> deleteWhereCount [FileContentChunkHash ==. unFileContentChunkKey cRef]
|
||||||
|
|
||||||
return ( fileContentChunkUnreferenced E.^. FileContentChunkUnreferencedHash
|
(Sum deletedChunks, Sum deletedChunkSize) <- runConduit $
|
||||||
, E.subSelectForeign fileContentChunkUnreferenced FileContentChunkUnreferencedHash $ E.length_ . (E.^. FileContentChunkContent)
|
getChunkCandidates
|
||||||
)
|
.| takeWhileTime (interval / 3)
|
||||||
|
.| persistentTokenBucketTakeC' TokenBucketPruneFiles (view $ _2 . _Value :: _ -> Word64)
|
||||||
|
.| C.mapM deleteChunk
|
||||||
|
.| C.fold
|
||||||
|
|
||||||
deleteChunk :: _ -> DB (Sum Natural, Sum Word64)
|
return (deletedEntries, deletedChunks, deletedChunkSize)
|
||||||
deleteChunk (E.Value cRef, E.Value size) = do
|
|
||||||
deleteWhere [ FileContentChunkUnreferencedHash ==. cRef ]
|
|
||||||
(, Sum size) . fromIntegral <$> deleteWhereCount [FileContentChunkHash ==. unFileContentChunkKey cRef]
|
|
||||||
|
|
||||||
(Sum deletedChunks, Sum deletedChunkSize) <- runConduit $
|
fin (deletedEntries, deletedChunks, deletedChunkSize) = do
|
||||||
getChunkCandidates
|
observeDeletedUnreferencedFiles deletedEntries
|
||||||
.| takeWhileTime (interval / 3)
|
$logInfoS "PruneUnreferencedFiles" [st|Deleted #{tshow deletedEntries} long-unreferenced files|]
|
||||||
.| persistentTokenBucketTakeC' TokenBucketPruneFiles (view $ _2 . _Value :: _ -> Word64)
|
observeDeletedUnreferencedChunks deletedChunks deletedChunkSize
|
||||||
.| C.mapM deleteChunk
|
$logInfoS "PruneUnreferencedFiles" [st|Deleted #{tshow deletedChunks} chunks (#{tshow deletedChunkSize} bytes)|]
|
||||||
.| C.fold
|
|
||||||
|
|
||||||
when (deletedChunks > 0 || deletedChunkSize > 0) $
|
|
||||||
$logInfoS "PruneUnreferencedFiles" [st|Deleted #{tshow deletedChunks} chunks (#{tshow deletedChunkSize} bytes)|]
|
|
||||||
|
|
||||||
|
|
||||||
dispatchJobInjectFiles :: JobHandler UniWorX
|
dispatchJobInjectFiles :: JobHandler UniWorX
|
||||||
@ -245,10 +251,10 @@ dispatchJobInjectFiles = JobHandlerException . maybeT (return ()) $ do
|
|||||||
.| maybe (C.map id) (takeWhileTime . (/ 2)) interval
|
.| maybe (C.map id) (takeWhileTime . (/ 2)) interval
|
||||||
.| transPipe (lift . runDB . setSerializable) (persistentTokenBucketTakeC' TokenBucketInjectFiles $ views _1 Minio.oiSize)
|
.| transPipe (lift . runDB . setSerializable) (persistentTokenBucketTakeC' TokenBucketInjectFiles $ views _1 Minio.oiSize)
|
||||||
.| C.mapM (lift . injectOrDelete)
|
.| C.mapM (lift . injectOrDelete)
|
||||||
|
.| C.mapM (\res@(Sum inj, Sum sz) -> res <$ observeRechunkedFiles inj sz)
|
||||||
.| C.fold
|
.| C.fold
|
||||||
|
|
||||||
when (injectedFiles > 0 || injectedSize > 0) $
|
$logInfoS "InjectFiles" [st|Injected #{tshow injectedFiles} files from upload cache into database (#{tshow injectedSize} bytes)|]
|
||||||
$logInfoS "InjectFiles" [st|Injected #{tshow injectedFiles} files from upload cache into database (#{tshow injectedSize} bytes)|]
|
|
||||||
|
|
||||||
|
|
||||||
data RechunkFileException
|
data RechunkFileException
|
||||||
@ -258,38 +264,42 @@ data RechunkFileException
|
|||||||
deriving anyclass (Exception)
|
deriving anyclass (Exception)
|
||||||
|
|
||||||
dispatchJobRechunkFiles :: JobHandler UniWorX
|
dispatchJobRechunkFiles :: JobHandler UniWorX
|
||||||
dispatchJobRechunkFiles = JobHandlerAtomic . hoist lift $ do
|
dispatchJobRechunkFiles = JobHandlerAtomicWithFinalizer act fin
|
||||||
interval <- getsYesod $ view _appRechunkFiles
|
where
|
||||||
let
|
act = hoist lift $ do
|
||||||
getEntryCandidates = E.selectSource . E.from $ \fileContentEntry -> E.distinctOnOrderBy [E.asc $ fileContentEntry E.^. FileContentEntryHash] $ do
|
interval <- getsYesod $ view _appRechunkFiles
|
||||||
E.where_ . E.exists . E.from $ \(fileContentEntry' `E.InnerJoin` fileContentChunk) -> do
|
let
|
||||||
E.on $ fileContentChunk E.^. FileContentChunkId E.==. fileContentEntry' E.^. FileContentEntryChunkHash
|
getEntryCandidates = E.selectSource . E.from $ \fileContentEntry -> E.distinctOnOrderBy [E.asc $ fileContentEntry E.^. FileContentEntryHash] $ do
|
||||||
E.where_ $ fileContentEntry' E.^. FileContentEntryHash E.==. fileContentEntry E.^. FileContentEntryHash
|
E.where_ . E.exists . E.from $ \(fileContentEntry' `E.InnerJoin` fileContentChunk) -> do
|
||||||
E.where_ . E.not_ $ fileContentChunk E.^. FileContentChunkContentBased
|
|
||||||
|
|
||||||
let size = E.subSelectMaybe . E.from $ \(fileContentEntry' `E.InnerJoin` fileContentChunk) -> do
|
|
||||||
E.on $ fileContentChunk E.^. FileContentChunkId E.==. fileContentEntry' E.^. FileContentEntryChunkHash
|
E.on $ fileContentChunk E.^. FileContentChunkId E.==. fileContentEntry' E.^. FileContentEntryChunkHash
|
||||||
E.where_ $ fileContentEntry' E.^. FileContentEntryHash E.==. fileContentEntry E.^. FileContentEntryHash
|
E.where_ $ fileContentEntry' E.^. FileContentEntryHash E.==. fileContentEntry E.^. FileContentEntryHash
|
||||||
return $ E.sum_ (E.length_ $ fileContentChunk E.^. FileContentChunkContent:: E.SqlExpr (E.Value Word64))
|
E.where_ . E.not_ $ fileContentChunk E.^. FileContentChunkContentBased
|
||||||
|
|
||||||
return ( fileContentEntry E.^. FileContentEntryHash
|
let size = E.subSelectMaybe . E.from $ \(fileContentEntry' `E.InnerJoin` fileContentChunk) -> do
|
||||||
, size
|
E.on $ fileContentChunk E.^. FileContentChunkId E.==. fileContentEntry' E.^. FileContentEntryChunkHash
|
||||||
)
|
E.where_ $ fileContentEntry' E.^. FileContentEntryHash E.==. fileContentEntry E.^. FileContentEntryHash
|
||||||
|
return $ E.sum_ (E.length_ $ fileContentChunk E.^. FileContentChunkContent:: E.SqlExpr (E.Value Word64))
|
||||||
|
|
||||||
rechunkFile :: FileContentReference -> Word64 -> DB (Sum Natural, Sum Word64)
|
return ( fileContentEntry E.^. FileContentEntryHash
|
||||||
rechunkFile fRef sz = do
|
, size
|
||||||
fRef' <- sinkFileDB True $ sourceFileDB fRef
|
)
|
||||||
unless (fRef == fRef') $
|
|
||||||
throwM $ RechunkFileExceptionHashMismatch fRef fRef'
|
|
||||||
return (Sum 1, Sum sz)
|
|
||||||
|
|
||||||
(Sum rechunkedFiles, Sum rechunkedSize) <- runConduit $
|
rechunkFile :: FileContentReference -> Word64 -> DB (Sum Natural, Sum Word64)
|
||||||
getEntryCandidates
|
rechunkFile fRef sz = do
|
||||||
.| C.mapMaybe (\(E.Value fRef, E.Value sz) -> (fRef, ) <$> sz)
|
fRef' <- sinkFileDB True $ sourceFileDB fRef
|
||||||
.| maybe (C.map id) (takeWhileTime . (/ 2)) interval
|
unless (fRef == fRef') $
|
||||||
.| persistentTokenBucketTakeC' TokenBucketRechunkFiles (view _2 :: _ -> Word64)
|
throwM $ RechunkFileExceptionHashMismatch fRef fRef'
|
||||||
.| C.mapM (uncurry rechunkFile)
|
return (Sum 1, Sum sz)
|
||||||
.| C.fold
|
|
||||||
|
|
||||||
when (rechunkedFiles > 0 || rechunkedSize > 0) $
|
(Sum rechunkedFiles, Sum rechunkedSize) <- runConduit $
|
||||||
$logInfoS "RechunkFiles" [st|Rechunked #{tshow rechunkedFiles} files in database (#{tshow rechunkedSize} bytes)|]
|
getEntryCandidates
|
||||||
|
.| C.mapMaybe (\(E.Value fRef, E.Value sz) -> (fRef, ) <$> sz)
|
||||||
|
.| maybe (C.map id) (takeWhileTime . (/ 2)) interval
|
||||||
|
.| persistentTokenBucketTakeC' TokenBucketRechunkFiles (view _2 :: _ -> Word64)
|
||||||
|
.| C.mapM (uncurry rechunkFile)
|
||||||
|
.| C.fold
|
||||||
|
|
||||||
|
return (rechunkedFiles, rechunkedSize)
|
||||||
|
fin (rechunkedFiles, rechunkedSize) = do
|
||||||
|
observeRechunkedFiles rechunkedFiles rechunkedSize
|
||||||
|
$logInfoS "RechunkFiles" [st|Rechunked #{tshow rechunkedFiles} files in database (#{tshow rechunkedSize} bytes)|]
|
||||||
|
|||||||
@ -8,8 +8,10 @@ import Database.Persist.Sql (deleteWhereCount)
|
|||||||
|
|
||||||
|
|
||||||
dispatchJobPruneFallbackPersonalisedSheetFilesKeys :: JobHandler UniWorX
|
dispatchJobPruneFallbackPersonalisedSheetFilesKeys :: JobHandler UniWorX
|
||||||
dispatchJobPruneFallbackPersonalisedSheetFilesKeys = JobHandlerAtomic . hoist lift $ do
|
dispatchJobPruneFallbackPersonalisedSheetFilesKeys = JobHandlerAtomicWithFinalizer act fin
|
||||||
now <- liftIO getCurrentTime
|
where
|
||||||
expires <- getsYesod $ view _appFallbackPersonalisedSheetFilesKeysExpire
|
act = hoist lift $ do
|
||||||
n <- deleteWhereCount [ FallbackPersonalisedSheetFilesKeyGenerated <. addUTCTime (- expires) now ]
|
now <- liftIO getCurrentTime
|
||||||
$logInfoS "PruneFallbackPersonalisedSheetFilesKeys" [st|Deleted #{n} expired fallback personalised sheet files keys|]
|
expires <- getsYesod $ view _appFallbackPersonalisedSheetFilesKeysExpire
|
||||||
|
deleteWhereCount [ FallbackPersonalisedSheetFilesKeyGenerated <. addUTCTime (- expires) now ]
|
||||||
|
fin n = $logInfoS "PruneFallbackPersonalisedSheetFilesKeys" [st|Deleted #{n} expired fallback personalised sheet files keys|]
|
||||||
|
|||||||
@ -7,7 +7,9 @@ import Import
|
|||||||
import Database.Persist.Sql (deleteWhereCount)
|
import Database.Persist.Sql (deleteWhereCount)
|
||||||
|
|
||||||
dispatchJobPruneInvitations :: JobHandler UniWorX
|
dispatchJobPruneInvitations :: JobHandler UniWorX
|
||||||
dispatchJobPruneInvitations = JobHandlerAtomic . hoist lift $ do
|
dispatchJobPruneInvitations = JobHandlerAtomicWithFinalizer act fin
|
||||||
now <- liftIO getCurrentTime
|
where
|
||||||
n <- deleteWhereCount [ InvitationExpiresAt <. Just now ]
|
act = hoist lift $ do
|
||||||
$logInfoS "PruneInvitations" [st|Deleted #{n} expired invitations|]
|
now <- liftIO getCurrentTime
|
||||||
|
deleteWhereCount [ InvitationExpiresAt <. Just now ]
|
||||||
|
fin n = $logInfoS "PruneInvitations" [st|Deleted #{n} expired invitations|]
|
||||||
|
|||||||
@ -9,23 +9,27 @@ import Handler.Utils.DateTime
|
|||||||
import Database.Persist.Sql (updateWhereCount, deleteWhereCount)
|
import Database.Persist.Sql (updateWhereCount, deleteWhereCount)
|
||||||
|
|
||||||
dispatchJobTruncateTransactionLog, dispatchJobDeleteTransactionLogIPs :: JobHandler UniWorX
|
dispatchJobTruncateTransactionLog, dispatchJobDeleteTransactionLogIPs :: JobHandler UniWorX
|
||||||
dispatchJobTruncateTransactionLog = JobHandlerAtomic . hoist lift $ do
|
dispatchJobTruncateTransactionLog = JobHandlerAtomicWithFinalizer act fin
|
||||||
now <- liftIO getCurrentTime
|
where
|
||||||
let localNow = utcToLocalTime now
|
act = hoist lift $ do
|
||||||
(localCurrentYear, _, _) = toGregorian $ localDay localNow
|
now <- liftIO getCurrentTime
|
||||||
localStartOfPreviousYear = LocalTime (fromGregorian (pred localCurrentYear) 1 1) midnight
|
let localNow = utcToLocalTime now
|
||||||
(currentYear, _, _) = toGregorian $ utctDay now
|
(localCurrentYear, _, _) = toGregorian $ localDay localNow
|
||||||
startOfPreviousYear = UTCTime (fromGregorian (pred currentYear) 1 1) 0
|
localStartOfPreviousYear = LocalTime (fromGregorian (pred localCurrentYear) 1 1) midnight
|
||||||
startOfPreviousYear' = case localTimeToUTC localStartOfPreviousYear of
|
(currentYear, _, _) = toGregorian $ utctDay now
|
||||||
LTUUnique utc' _ -> utc'
|
startOfPreviousYear = UTCTime (fromGregorian (pred currentYear) 1 1) 0
|
||||||
_other -> startOfPreviousYear
|
startOfPreviousYear' = case localTimeToUTC localStartOfPreviousYear of
|
||||||
|
LTUUnique utc' _ -> utc'
|
||||||
|
_other -> startOfPreviousYear
|
||||||
|
|
||||||
n <- deleteWhereCount [ TransactionLogTime <. startOfPreviousYear' ]
|
deleteWhereCount [ TransactionLogTime <. startOfPreviousYear' ]
|
||||||
$logInfoS "TruncateTransactionLog" [st|Deleted #{n} transaction log entries|]
|
fin n = $logInfoS "TruncateTransactionLog" [st|Deleted #{n} transaction log entries|]
|
||||||
dispatchJobDeleteTransactionLogIPs = JobHandlerAtomic . hoist lift $ do
|
dispatchJobDeleteTransactionLogIPs = JobHandlerAtomicWithFinalizer act fin
|
||||||
now <- liftIO getCurrentTime
|
where
|
||||||
retentionTime <- getsYesod $ view _appTransactionLogIPRetentionTime
|
act = hoist lift $ do
|
||||||
let cutoff = addUTCTime (- retentionTime) now
|
now <- liftIO getCurrentTime
|
||||||
|
retentionTime <- getsYesod $ view _appTransactionLogIPRetentionTime
|
||||||
|
let cutoff = addUTCTime (- retentionTime) now
|
||||||
|
|
||||||
n <- updateWhereCount [ TransactionLogTime <. cutoff, TransactionLogRemote !=. Nothing ] [ TransactionLogRemote =. Nothing ]
|
updateWhereCount [ TransactionLogTime <. cutoff, TransactionLogRemote !=. Nothing ] [ TransactionLogRemote =. Nothing ]
|
||||||
$logInfoS "DeleteTransactionLogIPs" [st|Deleted #{n} IP entries from transaction log|]
|
fin n = $logInfoS "DeleteTransactionLogIPs" [st|Deleted #{n} IP entries from transaction log|]
|
||||||
|
|||||||
@ -11,11 +11,10 @@ module Jobs.Types
|
|||||||
, JobContext(..)
|
, JobContext(..)
|
||||||
, JobState(..)
|
, JobState(..)
|
||||||
, jobWorkerNames
|
, jobWorkerNames
|
||||||
, JobWorkerState(..)
|
, JobWorkerState(..), _jobWorkerJobCtl, _jobWorkerJob
|
||||||
, withJobWorkerState
|
|
||||||
, JobWorkerId
|
, JobWorkerId
|
||||||
, showWorkerId, newWorkerId
|
, showWorkerId, newWorkerId
|
||||||
, JobQueue, jqInsert, jqDequeue
|
, JobQueue, jqInsert, jqDequeue, jqDepth
|
||||||
, JobPriority(..), prioritiseJob
|
, JobPriority(..), prioritiseJob
|
||||||
, jobNoQueueSame
|
, jobNoQueueSame
|
||||||
, module Cron
|
, module Cron
|
||||||
@ -38,10 +37,6 @@ import qualified Data.Set as Set
|
|||||||
import Data.PQueue.Prio.Max (MaxPQueue)
|
import Data.PQueue.Prio.Max (MaxPQueue)
|
||||||
import qualified Data.PQueue.Prio.Max as PQ
|
import qualified Data.PQueue.Prio.Max as PQ
|
||||||
|
|
||||||
import Utils.Metrics (withJobWorkerStateLbls)
|
|
||||||
|
|
||||||
import qualified Prometheus (Label4)
|
|
||||||
|
|
||||||
import Cron (CronNextMatch(..), _MatchAsap, _MatchAt, _MatchNone)
|
import Cron (CronNextMatch(..), _MatchAsap, _MatchAt, _MatchNone)
|
||||||
|
|
||||||
|
|
||||||
@ -179,7 +174,8 @@ type YesodJobDB site = ReaderT (YesodPersistBackend site) (WriterT (Set QueuedJo
|
|||||||
data JobHandler site
|
data JobHandler site
|
||||||
= JobHandlerAtomic (YesodJobDB site ())
|
= JobHandlerAtomic (YesodJobDB site ())
|
||||||
| JobHandlerException (HandlerFor site ())
|
| JobHandlerException (HandlerFor site ())
|
||||||
deriving (Generic, Typeable)
|
| forall a. JobHandlerAtomicWithFinalizer (YesodJobDB site a) (a -> HandlerFor site ())
|
||||||
|
deriving (Typeable)
|
||||||
|
|
||||||
makePrisms ''JobHandler
|
makePrisms ''JobHandler
|
||||||
|
|
||||||
@ -199,20 +195,6 @@ deriveJSON defaultOptions
|
|||||||
, sumEncoding = TaggedObject "state" "data"
|
, sumEncoding = TaggedObject "state" "data"
|
||||||
} ''JobWorkerState
|
} ''JobWorkerState
|
||||||
|
|
||||||
classifyJobWorkerState :: JobWorkerId -> JobWorkerState -> Prometheus.Label4
|
|
||||||
classifyJobWorkerState wId jws = (showWorkerId wId, tag, maybe "n/a" pack mJobCtl, maybe "n/a" pack mJob)
|
|
||||||
where
|
|
||||||
Aeson.Object obj = Aeson.toJSON jws
|
|
||||||
Aeson.String tag = obj HashMap.! "state"
|
|
||||||
mJobCtl = asum
|
|
||||||
[ classifyJobCtl <$> jws ^? _jobWorkerJobCtl
|
|
||||||
, "perform" <$ jws ^? _jobWorkerJob
|
|
||||||
]
|
|
||||||
mJob = classifyJob <$> jws ^? _jobWorkerJob
|
|
||||||
|
|
||||||
withJobWorkerState :: (MonadIO m, MonadMask m) => JobWorkerId -> JobWorkerState -> m a -> m a
|
|
||||||
withJobWorkerState wId newSt = withJobWorkerStateLbls $ classifyJobWorkerState wId newSt
|
|
||||||
|
|
||||||
|
|
||||||
newtype JobWorkerId = JobWorkerId { jobWorkerUnique :: Unique }
|
newtype JobWorkerId = JobWorkerId { jobWorkerUnique :: Unique }
|
||||||
deriving (Eq, Ord)
|
deriving (Eq, Ord)
|
||||||
@ -273,6 +255,9 @@ jqInsert job = force . over _JobQueue $ PQ.insertBehind (prioritiseJob job) job
|
|||||||
jqDequeue :: JobQueue -> Maybe (JobCtl, JobQueue)
|
jqDequeue :: JobQueue -> Maybe (JobCtl, JobQueue)
|
||||||
jqDequeue = fmap ((\r@(_, q) -> q `deepseq` r) . over _2 JobQueue) . PQ.maxView . getJobQueue
|
jqDequeue = fmap ((\r@(_, q) -> q `deepseq` r) . over _2 JobQueue) . PQ.maxView . getJobQueue
|
||||||
|
|
||||||
|
jqDepth :: Integral n => JobQueue -> n
|
||||||
|
jqDepth = fromIntegral . PQ.size . getJobQueue
|
||||||
|
|
||||||
|
|
||||||
data JobState = JobState
|
data JobState = JobState
|
||||||
{ jobWorkers :: Map (Async ()) (TVar JobQueue)
|
{ jobWorkers :: Map (Async ()) (TVar JobQueue)
|
||||||
|
|||||||
@ -1,14 +1,18 @@
|
|||||||
|
{-# OPTIONS_GHC -fno-warn-incomplete-uni-patterns #-}
|
||||||
|
|
||||||
module Utils.Metrics
|
module Utils.Metrics
|
||||||
( withHealthReportMetrics
|
( withHealthReportMetrics
|
||||||
, registerGHCMetrics
|
, registerGHCMetrics
|
||||||
, observeHTTPRequestLatency
|
, observeHTTPRequestLatency
|
||||||
, registerReadyMetric
|
, registerReadyMetric
|
||||||
, registerJobHeldLocksCount
|
, withJobWorkerState
|
||||||
, withJobWorkerStateLbls
|
|
||||||
, observeYesodCacheSize
|
, observeYesodCacheSize
|
||||||
, observeFavouritesQuickActionsDuration
|
, observeFavouritesQuickActionsDuration
|
||||||
, LoginOutcome(..), observeLoginOutcome
|
, LoginOutcome(..), observeLoginOutcome
|
||||||
|
, registerJobHeldLocksCount
|
||||||
, FileChunkStorage(..), observeSourcedChunk, observeSunkChunk
|
, FileChunkStorage(..), observeSourcedChunk, observeSunkChunk
|
||||||
|
, observeDeletedUnreferencedFiles, observeDeletedUnreferencedChunks, observeInjectedFiles, observeRechunkedFiles
|
||||||
|
, registerJobWorkerQueueDepth
|
||||||
) where
|
) where
|
||||||
|
|
||||||
import Import.NoModel hiding (Vector, Info)
|
import Import.NoModel hiding (Vector, Info)
|
||||||
@ -29,6 +33,11 @@ import Yesod.Core.Types (HandlerData(..), GHState(..))
|
|||||||
|
|
||||||
import qualified Data.Set as Set
|
import qualified Data.Set as Set
|
||||||
|
|
||||||
|
import Jobs.Types
|
||||||
|
|
||||||
|
import qualified Data.Aeson as Aeson
|
||||||
|
import qualified Data.HashMap.Strict as HashMap
|
||||||
|
|
||||||
{-# ANN module ("HLint: ignore Use even" :: String) #-}
|
{-# ANN module ("HLint: ignore Use even" :: String) #-}
|
||||||
|
|
||||||
|
|
||||||
@ -130,15 +139,75 @@ jobHeldLocksCount heldLocks = Metric $ return (MkJobHeldLocksCount, collectJobHe
|
|||||||
sourcedFileChunkSizes :: Vector Label1 Histogram
|
sourcedFileChunkSizes :: Vector Label1 Histogram
|
||||||
sourcedFileChunkSizes = unsafeRegister . vector "storage" $ histogram info buckets
|
sourcedFileChunkSizes = unsafeRegister . vector "storage" $ histogram info buckets
|
||||||
where info = Info "uni2work_sourced_file_chunks_bytes"
|
where info = Info "uni2work_sourced_file_chunks_bytes"
|
||||||
"Sizes of files chunks sourced"
|
"Sizes of file chunks sourced"
|
||||||
buckets = 0 : histogramBuckets 1 20000000
|
buckets = 0 : histogramBuckets 1 1000000000
|
||||||
|
|
||||||
{-# NOINLINE sunkFileChunkSizes #-}
|
{-# NOINLINE sunkFileChunkSizes #-}
|
||||||
sunkFileChunkSizes :: Vector Label1 Histogram
|
sunkFileChunkSizes :: Vector Label1 Histogram
|
||||||
sunkFileChunkSizes = unsafeRegister . vector "storage" $ histogram info buckets
|
sunkFileChunkSizes = unsafeRegister . vector "storage" $ histogram info buckets
|
||||||
where info = Info "uni2work_sunk_file_chunks_bytes"
|
where info = Info "uni2work_sunk_file_chunks_bytes"
|
||||||
"Sizes of files chunks sunk"
|
"Sizes of file chunks sunk"
|
||||||
buckets = 0 : histogramBuckets 1 100000000
|
buckets = 0 : histogramBuckets 1 1000000000
|
||||||
|
|
||||||
|
{-# NOINLINE deletedUnreferencedFiles #-}
|
||||||
|
deletedUnreferencedFiles :: Counter
|
||||||
|
deletedUnreferencedFiles = unsafeRegister $ counter info
|
||||||
|
where info = Info "uni2work_deleted_unreferenced_files_count"
|
||||||
|
"Number of unreferenced files deleted"
|
||||||
|
|
||||||
|
{-# NOINLINE deletedUnreferencedChunks #-}
|
||||||
|
deletedUnreferencedChunks :: Counter
|
||||||
|
deletedUnreferencedChunks = unsafeRegister $ counter info
|
||||||
|
where info = Info "uni2work_deleted_unreferenced_chunks_count"
|
||||||
|
"Number of unreferenced chunks deleted"
|
||||||
|
|
||||||
|
{-# NOINLINE deletedUnreferencedChunksBytes #-}
|
||||||
|
deletedUnreferencedChunksBytes :: Counter
|
||||||
|
deletedUnreferencedChunksBytes = unsafeRegister $ counter info
|
||||||
|
where info = Info "uni2work_deleted_unreferenced_chunks_bytes"
|
||||||
|
"Size of unreferenced chunks deleted"
|
||||||
|
|
||||||
|
{-# NOINLINE injectedFiles #-}
|
||||||
|
injectedFiles :: Counter
|
||||||
|
injectedFiles = unsafeRegister $ counter info
|
||||||
|
where info = Info "uni2work_injected_files_count"
|
||||||
|
"Number of files injected from upload cache into database"
|
||||||
|
|
||||||
|
{-# NOINLINE injectedFilesBytes #-}
|
||||||
|
injectedFilesBytes :: Counter
|
||||||
|
injectedFilesBytes = unsafeRegister $ counter info
|
||||||
|
where info = Info "uni2work_injected_files_bytes"
|
||||||
|
"Size of files injected from upload cache into database"
|
||||||
|
|
||||||
|
{-# NOINLINE rechunkedFiles #-}
|
||||||
|
rechunkedFiles :: Counter
|
||||||
|
rechunkedFiles = unsafeRegister $ counter info
|
||||||
|
where info = Info "uni2work_rechunked_files_count"
|
||||||
|
"Number of files rechunked within database"
|
||||||
|
|
||||||
|
{-# NOINLINE rechunkedFilesBytes #-}
|
||||||
|
rechunkedFilesBytes :: Counter
|
||||||
|
rechunkedFilesBytes = unsafeRegister $ counter info
|
||||||
|
where info = Info "uni2work_rechunked_files_bytes"
|
||||||
|
"Size of files rechunked within database"
|
||||||
|
|
||||||
|
data JobWorkerQueueDepth = MkJobWorkerQueueDepth
|
||||||
|
|
||||||
|
jobWorkerQueueDepth :: TMVar JobState -> Metric JobWorkerQueueDepth
|
||||||
|
jobWorkerQueueDepth jSt = Metric $ return (MkJobWorkerQueueDepth, collectJobWorkerQueueDepth)
|
||||||
|
where
|
||||||
|
collectJobWorkerQueueDepth = maybeT (return []) $ do
|
||||||
|
wQueues <- hoist atomically $ do
|
||||||
|
JobState{..} <- MaybeT $ tryReadTMVar jSt
|
||||||
|
flip ifoldMapM jobWorkers $ \wAsync wQueue
|
||||||
|
-> lift $ pure . (jobWorkerName wAsync, ) . jqDepth <$> readTVar wQueue
|
||||||
|
return [ SampleGroup info GaugeType
|
||||||
|
[ Sample "uni2work_queued_jobs_count" [("worker", showWorkerId wName)] . encodeUtf8 $ tshow wDepth
|
||||||
|
| (wName, wDepth) <- wQueues
|
||||||
|
]
|
||||||
|
]
|
||||||
|
info = Info "uni2work_queued_jobs_count"
|
||||||
|
"Number of JobQueue entries in this Uni2work-instance"
|
||||||
|
|
||||||
withHealthReportMetrics :: MonadIO m => m HealthReport -> m HealthReport
|
withHealthReportMetrics :: MonadIO m => m HealthReport -> m HealthReport
|
||||||
withHealthReportMetrics act = do
|
withHealthReportMetrics act = do
|
||||||
@ -181,6 +250,20 @@ observeHTTPRequestLatency classifyHandler app req respond' = do
|
|||||||
registerReadyMetric :: MonadIO m => m ()
|
registerReadyMetric :: MonadIO m => m ()
|
||||||
registerReadyMetric = liftIO $ void . register . readyMetric =<< getPOSIXTime
|
registerReadyMetric = liftIO $ void . register . readyMetric =<< getPOSIXTime
|
||||||
|
|
||||||
|
classifyJobWorkerState :: JobWorkerId -> JobWorkerState -> Prometheus.Label4
|
||||||
|
classifyJobWorkerState wId jws = (showWorkerId wId, tag, maybe "n/a" pack mJobCtl, maybe "n/a" pack mJob)
|
||||||
|
where
|
||||||
|
Aeson.Object obj = Aeson.toJSON jws
|
||||||
|
Aeson.String tag = obj HashMap.! "state"
|
||||||
|
mJobCtl = asum
|
||||||
|
[ classifyJobCtl <$> jws ^? _jobWorkerJobCtl
|
||||||
|
, "perform" <$ jws ^? _jobWorkerJob
|
||||||
|
]
|
||||||
|
mJob = classifyJob <$> jws ^? _jobWorkerJob
|
||||||
|
|
||||||
|
withJobWorkerState :: (MonadIO m, MonadMask m) => JobWorkerId -> JobWorkerState -> m a -> m a
|
||||||
|
withJobWorkerState wId newSt = withJobWorkerStateLbls $ classifyJobWorkerState wId newSt
|
||||||
|
|
||||||
withJobWorkerStateLbls :: (MonadIO m, MonadMask m) => Label4 -> m a -> m a
|
withJobWorkerStateLbls :: (MonadIO m, MonadMask m) => Label4 -> m a -> m a
|
||||||
withJobWorkerStateLbls newLbls act = do
|
withJobWorkerStateLbls newLbls act = do
|
||||||
liftIO $ withLabel jobWorkerStateTransitions newLbls incCounter
|
liftIO $ withLabel jobWorkerStateTransitions newLbls incCounter
|
||||||
@ -240,3 +323,24 @@ observeSourcedChunk store = liftIO . observeChunkSize sourcedFileChunkSizes stor
|
|||||||
|
|
||||||
observeChunkSize :: Vector Label1 Histogram -> FileChunkStorage -> Integer -> IO ()
|
observeChunkSize :: Vector Label1 Histogram -> FileChunkStorage -> Integer -> IO ()
|
||||||
observeChunkSize metric (toPathPiece -> storageLabel) = withLabel metric storageLabel . flip observe . fromInteger
|
observeChunkSize metric (toPathPiece -> storageLabel) = withLabel metric storageLabel . flip observe . fromInteger
|
||||||
|
|
||||||
|
observeDeletedUnreferencedFiles :: MonadIO m => Natural -> m ()
|
||||||
|
observeDeletedUnreferencedFiles = liftIO . void . addCounter deletedUnreferencedFiles . fromIntegral
|
||||||
|
|
||||||
|
observeDeletedUnreferencedChunks :: MonadIO m => Natural -> Word64 -> m ()
|
||||||
|
observeDeletedUnreferencedChunks num size = liftIO $ do
|
||||||
|
void . addCounter deletedUnreferencedChunks $ fromIntegral num
|
||||||
|
void . addCounter deletedUnreferencedChunksBytes $ fromIntegral size
|
||||||
|
|
||||||
|
observeInjectedFiles :: MonadIO m => Natural -> Word64 -> m ()
|
||||||
|
observeInjectedFiles num size = liftIO $ do
|
||||||
|
void . addCounter injectedFiles $ fromIntegral num
|
||||||
|
void . addCounter injectedFilesBytes $ fromIntegral size
|
||||||
|
|
||||||
|
observeRechunkedFiles :: MonadIO m => Natural -> Word64 -> m ()
|
||||||
|
observeRechunkedFiles num size = liftIO $ do
|
||||||
|
void . addCounter rechunkedFiles $ fromIntegral num
|
||||||
|
void . addCounter rechunkedFilesBytes $ fromIntegral size
|
||||||
|
|
||||||
|
registerJobWorkerQueueDepth :: MonadIO m => TMVar JobState -> m ()
|
||||||
|
registerJobWorkerQueueDepth = liftIO . void . register . jobWorkerQueueDepth
|
||||||
|
|||||||
Reference in New Issue
Block a user