graphql-engine/server/src-lib/Hasura/RQL/DDL/ScheduledTrigger.hs

202 lines
5.8 KiB
Haskell
Raw Normal View History

module Hasura.RQL.DDL.ScheduledTrigger
( runCreateCronTrigger,
runDeleteCronTrigger,
dropCronTriggerInMetadata,
resolveCronTrigger,
runCreateScheduledEvent,
runDeleteScheduledEvent,
runGetScheduledEvents,
runGetEventInvocations,
populateInitialCronTriggerEvents,
)
where
import Data.Aeson qualified as J
import Data.Environment qualified as Env
import Data.HashMap.Strict qualified as Map
import Data.HashMap.Strict.InsOrd qualified as OMap
import Data.Time.Clock qualified as C
import Hasura.Base.Error
import Hasura.EncJSON
import Hasura.Eventing.ScheduledTrigger
import Hasura.Metadata.Class
import Hasura.Prelude
import Hasura.RQL.DDL.EventTrigger (getHeaderInfosFromConf)
import Hasura.RQL.Types
import System.Cron.Types (CronSchedule)
populateInitialCronTriggerEvents ::
( MonadIO m,
MonadMetadataStorageQueryAPI m
) =>
CronSchedule ->
TriggerName ->
m ()
populateInitialCronTriggerEvents schedule triggerName = do
currentTime <- liftIO C.getCurrentTime
let scheduleTimes = generateScheduleTimes currentTime 100 schedule
insertCronEvents $ map (CronEventSeed triggerName) scheduleTimes
pure ()
-- | runCreateCronTrigger will update a existing cron trigger when the 'replace'
-- value is set to @true@ and when replace is @false@ a new cron trigger will
-- be created
runCreateCronTrigger ::
( CacheRWM m,
MonadIO m,
MetadataM m,
MonadMetadataStorageQueryAPI m
) =>
CreateCronTrigger ->
m EncJSON
runCreateCronTrigger CreateCronTrigger {..} = do
let q =
CronTriggerMetadata
cctName
cctWebhook
cctCronSchedule
cctPayload
cctRetryConf
cctHeaders
cctIncludeInMetadata
cctComment
case cctReplace of
True -> updateCronTrigger q
False -> do
cronTriggersMap <- scCronTriggers <$> askSchemaCache
case Map.lookup (ctName q) cronTriggersMap of
Nothing -> pure ()
Just _ ->
throw400 AlreadyExists $
"cron trigger with name: "
<> triggerNameToTxt (ctName q)
<> " already exists"
let metadataObj = MOCronTrigger cctName
metadata =
CronTriggerMetadata
cctName
cctWebhook
cctCronSchedule
cctPayload
cctRetryConf
cctHeaders
cctIncludeInMetadata
cctComment
buildSchemaCacheFor metadataObj $
MetadataModifier $
metaCronTriggers %~ OMap.insert cctName metadata
populateInitialCronTriggerEvents cctCronSchedule cctName
return successMsg
resolveCronTrigger ::
(QErrM m) =>
Env.Environment ->
CronTriggerMetadata ->
m CronTriggerInfo
resolveCronTrigger env CronTriggerMetadata {..} = do
webhookInfo <- resolveWebhook env ctWebhook
headerInfo <- getHeaderInfosFromConf env ctHeaders
pure $
CronTriggerInfo
ctName
ctSchedule
ctPayload
ctRetryConf
webhookInfo
headerInfo
ctComment
updateCronTrigger ::
( CacheRWM m,
MonadIO m,
MetadataM m,
MonadMetadataStorageQueryAPI m
) =>
CronTriggerMetadata ->
m EncJSON
updateCronTrigger cronTriggerMetadata = do
let triggerName = ctName cronTriggerMetadata
checkExists triggerName
buildSchemaCacheFor (MOCronTrigger triggerName) $
MetadataModifier $
metaCronTriggers %~ OMap.insert triggerName cronTriggerMetadata
dropFutureCronEvents $ SingleCronTrigger triggerName
currentTime <- liftIO C.getCurrentTime
let scheduleTimes = generateScheduleTimes currentTime 100 $ ctSchedule cronTriggerMetadata
insertCronEvents $ map (CronEventSeed triggerName) scheduleTimes
pure successMsg
runDeleteCronTrigger ::
( CacheRWM m,
MetadataM m,
MonadMetadataStorageQueryAPI m
) =>
ScheduledTriggerName ->
m EncJSON
runDeleteCronTrigger (ScheduledTriggerName stName) = do
checkExists stName
withNewInconsistentObjsCheck $
buildSchemaCache $
dropCronTriggerInMetadata stName
dropFutureCronEvents $ SingleCronTrigger stName
return successMsg
dropCronTriggerInMetadata :: TriggerName -> MetadataModifier
dropCronTriggerInMetadata name =
MetadataModifier $ metaCronTriggers %~ OMap.delete name
runCreateScheduledEvent ::
(MonadMetadataStorageQueryAPI m) =>
CreateScheduledEvent ->
m EncJSON
runCreateScheduledEvent scheduledEvent = do
eid <- createOneOffScheduledEvent scheduledEvent
pure $ encJFromJValue $ J.object ["message" J..= J.String "success", "event_id" J..= eid]
checkExists :: (CacheRM m, MonadError QErr m) => TriggerName -> m ()
checkExists name = do
cronTriggersMap <- scCronTriggers <$> askSchemaCache
void $
onNothing (Map.lookup name cronTriggersMap) $
throw400 NotExists $
"cron trigger with name: " <> triggerNameToTxt name <> " does not exist"
runDeleteScheduledEvent ::
(MonadMetadataStorageQueryAPI m) => DeleteScheduledEvent -> m EncJSON
runDeleteScheduledEvent DeleteScheduledEvent {..} = do
dropEvent _dseEventId _dseType
pure successMsg
runGetScheduledEvents ::
( CacheRM m,
MonadMetadataStorageQueryAPI m
) =>
GetScheduledEvents ->
m EncJSON
runGetScheduledEvents gse = do
case _gseScheduledEvent gse of
SEOneOff -> pure ()
SECron name -> checkExists name
encJFromJValue <$> fetchScheduledEvents gse
runGetEventInvocations ::
( CacheRM m,
MonadMetadataStorageQueryAPI m
) =>
GetEventInvocations ->
m EncJSON
runGetEventInvocations GetEventInvocations {..} = do
case _geiInvocationsBy of
GIBEventId _ _ -> pure ()
GIBEvent event -> case event of
SEOneOff -> pure ()
SECron name -> checkExists name
WithTotalCount count invocations <- fetchInvocations _geiInvocationsBy _geiPagination
pure $
encJFromJValue $
J.object
[ "invocations" J..= invocations,
"count" J..= count
]