chore(job): add sleep job for testing

also show running job workers
This commit is contained in:
Steffen Jost 2025-03-10 18:24:17 +01:00
parent 6b32cddeac
commit ee5a79398f
4 changed files with 46 additions and 21 deletions

View File

@ -14,4 +14,6 @@ log-settings:
destination: test.log destination: test.log
auth-dummy-login: true auth-dummy-login: true
server-session-acid-fallback: true server-session-acid-fallback: true
job-workers: 20

View File

@ -17,7 +17,7 @@ import Handler.Utils
-- import Data.Aeson (fromJSON) -- import Data.Aeson (fromJSON)
-- import qualified Data.Aeson as Aeson -- import qualified Data.Aeson as Aeson
-- import qualified Data.Aeson.Types as Aeson -- import qualified Data.Aeson.Types as Aeson
import qualified Data.Aeson.Encode.Pretty as Pretty import qualified Data.Aeson.Encode.Pretty as Pretty
-- import qualified Data.CaseInsensitive as CI -- import qualified Data.CaseInsensitive as CI
import qualified Data.Text as Text import qualified Data.Text as Text
@ -37,13 +37,13 @@ import qualified Database.Esqueleto.Utils as E
-- Number of minutes a job must have been locked already to allow forced deletion -- Number of minutes a job must have been locked already to allow forced deletion
jobDeleteLockMinutes :: Int jobDeleteLockMinutes :: Int
jobDeleteLockMinutes = 3 jobDeleteLockMinutes = 3
deriveJSON defaultOptions deriveJSON defaultOptions
{ constructorTagModifier = camelToPathPiece' 1 { constructorTagModifier = camelToPathPiece' 1
} ''CronNextMatch } ''CronNextMatch
getAdminCrontabR :: Handler TypedContent getAdminCrontabR :: Handler TypedContent
getAdminCrontabR = do getAdminCrontabR = do
jState <- getsYesod appJobState jState <- getsYesod appJobState
@ -64,7 +64,7 @@ getAdminCrontabR = do
encodeBearer =<< bearerToken (HashSet.singleton . Left $ toJSON UserGroupCrontab) Nothing (HashMap.singleton BearerTokenRouteEval $ HashSet.singleton AdminCrontabR) Nothing (Just Nothing) Nothing encodeBearer =<< bearerToken (HashSet.singleton . Left $ toJSON UserGroupCrontab) Nothing (HashMap.singleton BearerTokenRouteEval $ HashSet.singleton AdminCrontabR) Nothing (Just Nothing) Nothing
siteLayoutMsg MsgHeadingAdminCrontab $ do siteLayoutMsg MsgHeadingAdminCrontab $ do
setTitleI MsgHeadingAdminCrontab setTitleI MsgHeadingAdminCrontab
[whamlet| [whamlet|
@ -121,7 +121,7 @@ instance Finite JobTableAction
nullaryPathPiece ''JobTableAction $ camelToPathPiece' 1 nullaryPathPiece ''JobTableAction $ camelToPathPiece' 1
embedRenderMessage ''UniWorX ''JobTableAction id embedRenderMessage ''UniWorX ''JobTableAction id
newtype JobTableActionData = ActJobDeleteData newtype JobTableActionData = ActJobDeleteData
{ jobDeleteLocked :: Bool { jobDeleteLocked :: Bool
} }
deriving (Eq, Ord, Read, Show, Generic) deriving (Eq, Ord, Read, Show, Generic)
@ -151,7 +151,7 @@ postAdminJobsR = do
, sortable (Just "lock-instance") (i18nCell MsgTableJobLockInstance) $ \(view $ resultJob . _entityVal -> QueuedJob{..}) -> cellMaybe (stringCell . show) queuedJobLockInstance , sortable (Just "lock-instance") (i18nCell MsgTableJobLockInstance) $ \(view $ resultJob . _entityVal -> QueuedJob{..}) -> cellMaybe (stringCell . show) queuedJobLockInstance
, sortable (Just "creation-instance") (i18nCell MsgTableJobCreationInstance) $ \(view $ resultJob . _entityVal -> QueuedJob{..}) -> stringCell $ show queuedJobCreationInstance , sortable (Just "creation-instance") (i18nCell MsgTableJobCreationInstance) $ \(view $ resultJob . _entityVal -> QueuedJob{..}) -> stringCell $ show queuedJobCreationInstance
] ]
dbtSorting = Map.fromList dbtSorting = Map.fromList
[ ("creation-time" , SortColumnNullsInv (E.^. QueuedJobCreationTime)) [ ("creation-time" , SortColumnNullsInv (E.^. QueuedJobCreationTime))
, ("job" , SortColumn (\v -> v E.^. QueuedJobContent E.->>. "job")) , ("job" , SortColumn (\v -> v E.^. QueuedJobContent E.->>. "job"))
, ("content" , SortColumn (E.^. QueuedJobContent)) , ("content" , SortColumn (E.^. QueuedJobContent))
@ -171,8 +171,8 @@ postAdminJobsR = do
acts :: Map JobTableAction (AForm Handler JobTableActionData) acts :: Map JobTableAction (AForm Handler JobTableActionData)
acts = Map.singleton ActJobDelete $ ActJobDeleteData acts = Map.singleton ActJobDelete $ ActJobDeleteData
<$> areq checkBoxField (fslI $ MsgActJobDeleteForce jobDeleteLockMinutes) Nothing <$> areq checkBoxField (fslI $ MsgActJobDeleteForce jobDeleteLockMinutes) Nothing
dbtParams = DBParamsForm dbtParams = DBParamsForm
{ dbParamsFormAdditional = { dbParamsFormAdditional =
renderAForm FormStandard renderAForm FormStandard
$ (, mempty) . First . Just $ (, mempty) . First . Just
<$> multiActionA acts (fslI MsgTableAction) Nothing <$> multiActionA acts (fslI MsgTableAction) Nothing
@ -188,14 +188,15 @@ postAdminJobsR = do
dbtCsvDecode = Nothing dbtCsvDecode = Nothing
dbtExtraReps = [] dbtExtraReps = []
-- jobsDBTableValidator :: PSValidator (MForm Handler) (FormResult (First JobTableAction, DBFormResult QueuedJobId Bool (DBRow (Entity QueuedJob)))) -- jobsDBTableValidator :: PSValidator (MForm Handler) (FormResult (First JobTableAction, DBFormResult QueuedJobId Bool (DBRow (Entity QueuedJob))))
jobsDBTableValidator = def jobsDBTableValidator = def
& defaultSorting [SortDescBy "creation-time"] & defaultSorting [SortDescBy "creation-time"]
postprocess :: FormResult (First JobTableActionData, DBFormResult QueuedJobId Bool (DBRow (Entity QueuedJob))) postprocess :: FormResult (First JobTableActionData, DBFormResult QueuedJobId Bool (DBRow (Entity QueuedJob)))
-> FormResult (JobTableActionData, Set QueuedJobId) -> FormResult (JobTableActionData, Set QueuedJobId)
postprocess inp = do postprocess inp = do
(First (Just act), jobMap) <- inp (First (Just act), jobMap) <- inp
let jobSet = Map.keysSet . Map.filter id $ getDBFormResult (const False) jobMap let jobSet = Map.keysSet . Map.filter id $ getDBFormResult (const False) jobMap
return (act, jobSet) return (act, jobSet)
void . queueJob' $ JobSleep 42 -- debug add sleep job
(jobActRes, jobsTable) <- runDB (over _1 postprocess <$> dbTable jobsDBTableValidator jobsDBTable) (jobActRes, jobsTable) <- runDB (over _1 postprocess <$> dbTable jobsDBTableValidator jobsDBTable)
formResult jobActRes $ \case formResult jobActRes $ \case
@ -205,24 +206,33 @@ postAdminJobsR = do
cutoff = addUTCTime (nominalMinute * fromIntegral (negate jobDeleteLockMinutes)) now cutoff = addUTCTime (nominalMinute * fromIntegral (negate jobDeleteLockMinutes)) now
jobReq = length jobIds jobReq = length jobIds
lockCriteria lockCriteria
| jobDeleteLocked = | jobDeleteLocked =
[ QueuedJobLockTime ==. Nothing ] ||. [ QueuedJobLockTime ==. Nothing ] ||.
[ QueuedJobLockTime <=. Just cutoff ] [ QueuedJobLockTime <=. Just cutoff ]
| otherwise = | otherwise =
[ QueuedJobLockTime ==. Nothing [ QueuedJobLockTime ==. Nothing
, QueuedJobLockInstance ==. Nothing , QueuedJobLockInstance ==. Nothing
] ]
rmvd <- runDB $ fromIntegral <$> deleteWhereCount rmvd <- runDB $ fromIntegral <$> deleteWhereCount
((QueuedJobId <-. Set.toList jobIds) : lockCriteria) ((QueuedJobId <-. Set.toList jobIds) : lockCriteria)
addMessageI (bool Success Warning $ rmvd < jobReq) (MsgTableJobActDeleteFeedback rmvd jobReq) addMessageI (bool Success Warning $ rmvd < jobReq) (MsgTableJobActDeleteFeedback rmvd jobReq)
reloadKeepGetParams AdminJobsR reloadKeepGetParams AdminJobsR
-- gather some data on job worles
(nrWorkers, jobStateVar) <- getsYesod (view _appJobWorkers &&& appJobState)
jState <- atomically $ tryReadTMVar jobStateVar
let running = Map.size . jobWorkers <$> jState
siteLayoutMsg MsgMenuAdminJobs $ do siteLayoutMsg MsgMenuAdminJobs $ do
setTitleI MsgMenuAdminJobs setTitleI MsgMenuAdminJobs
[whamlet| [whamlet|
^{jobsTable} <section>
^{jobsTable}
<section>
<ul>
<li> #{running} job workers currently running
<li> #{nrWorkers} job workers configured to run
|] |]
where where
doEnc :: ToJSON a => a -> _ doEnc :: ToJSON a => a -> _
@ -232,8 +242,8 @@ postAdminJobsR = do
, Text.splitOn "-" t , Text.splitOn "-" t
) )
} }
getJobName :: Value -> Maybe Text getJobName :: Value -> Maybe Text
getJobName (Object o) getJobName (Object o)
| Just (String s) <- HashMap.lookup "job" o = Just s -- (kebabToCamel s) | Just (String s) <- HashMap.lookup "job" o = Just s -- (kebabToCamel s)
getJobName _ = Nothing getJobName _ = Nothing

View File

@ -4,6 +4,7 @@
module Jobs.Handler.SendTestEmail module Jobs.Handler.SendTestEmail
( dispatchJobSendTestEmail ( dispatchJobSendTestEmail
, dispatchJobSleep
) where ) where
import Import import Import
@ -14,6 +15,8 @@ import Text.Hamlet
-- import Handler.Utils.I18n -- import Handler.Utils.I18n
-- import Text.Blaze.Internal -- import Text.Blaze.Internal
import UnliftIO.Concurrent (threadDelay)
dispatchJobSendTestEmail :: Email -> MailContext -> JobHandler UniWorX dispatchJobSendTestEmail :: Email -> MailContext -> JobHandler UniWorX
dispatchJobSendTestEmail jEmail jMailContext = JobHandlerException . mailT jMailContext $ do dispatchJobSendTestEmail jEmail jMailContext = JobHandlerException . mailT jMailContext $ do
_mailTo .= [Address Nothing jEmail] _mailTo .= [Address Nothing jEmail]
@ -58,6 +61,15 @@ dispatchJobSendTestEmail jEmail jMailContext = JobHandlerException . mailT jMail
--test <- liftHandler $ withUrlRenderer $(i18nHamletFile "test") --test <- liftHandler $ withUrlRenderer $(i18nHamletFile "test")
test :: Html <- liftHandler $ withUrlRenderer $(hamletFile "templates/i18n/test/en-eu.hamlet") test :: Html <- liftHandler $ withUrlRenderer $(hamletFile "templates/i18n/test/en-eu.hamlet")
addHtmlMarkdownAlternatives test addHtmlMarkdownAlternatives test
-- --
--test2 <- liftHandler $(i18nHamletFile "test") --test2 <- liftHandler $(i18nHamletFile "test")
--addHtmlMarkdownAlternatives test2 --addHtmlMarkdownAlternatives test2
dispatchJobSleep :: Int -> JobHandler UniWorX
dispatchJobSleep sleepTime = JobHandlerAtomic act
where
act = do
$logInfoS "JOBS" [st|Sleep job #{sleepTime}s started.|]
threadDelay (sleepTime * 1000000)
$logInfoS "JOBS" [st|Sleep job #{sleepTime}s ended.|]

View File

@ -141,8 +141,9 @@ data Job
| JobLmsReports { jQualification :: QualificationId } | JobLmsReports { jQualification :: QualificationId }
| JobPrintAck | JobPrintAck
| JobPrintAckAgain | JobPrintAckAgain
| JobSleep { jSleep :: Int } -- dummy job that just sleeps to test job system
deriving (Eq, Ord, Show, Read, Generic) deriving (Eq, Ord, Show, Read, Generic)
data Notification data Notification
= NotificationSubmissionRated { nSubmission :: SubmissionId } = NotificationSubmissionRated { nSubmission :: SubmissionId }
| NotificationSheetActive { nSheet :: SheetId } | NotificationSheetActive { nSheet :: SheetId }