mirror of
https://github.com/hasura/graphql-engine.git
synced 2024-12-17 20:41:49 +03:00
7cc33dd8ec
- Remove `MonadMetadataStorageQueryAPI` which was only implemented by a default implementation - Introduce `TransT` which can be used to easily derive `lift`ing implementations for `MonadBlaBlaBla` classes PR-URL: https://github.com/hasura/graphql-engine-mono/pull/8579 GitOrigin-RevId: 4f804fda7e2de5c9d75ee4df269f500ebd46b8c9
229 lines
7.0 KiB
Haskell
229 lines
7.0 KiB
Haskell
module Hasura.RQL.DDL.ScheduledTrigger
|
|
( runCreateCronTrigger,
|
|
runDeleteCronTrigger,
|
|
dropCronTriggerInMetadata,
|
|
resolveCronTrigger,
|
|
runCreateScheduledEvent,
|
|
runDeleteScheduledEvent,
|
|
runGetScheduledEvents,
|
|
runGetScheduledEventInvocations,
|
|
populateInitialCronTriggerEvents,
|
|
runGetCronTriggers,
|
|
)
|
|
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 Data.URL.Template (printURLTemplate)
|
|
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.Common
|
|
import Hasura.RQL.Types.EventTrigger
|
|
import Hasura.RQL.Types.Metadata
|
|
import Hasura.RQL.Types.Metadata.Object
|
|
import Hasura.RQL.Types.ScheduledTrigger
|
|
import Hasura.RQL.Types.SchemaCache
|
|
import Hasura.RQL.Types.SchemaCache.Build
|
|
import System.Cron.Types (CronSchedule)
|
|
|
|
populateInitialCronTriggerEvents ::
|
|
( MonadIO m,
|
|
MonadError QErr m,
|
|
MonadMetadataStorage m
|
|
) =>
|
|
CronSchedule ->
|
|
TriggerName ->
|
|
m ()
|
|
populateInitialCronTriggerEvents schedule triggerName = do
|
|
currentTime <- liftIO C.getCurrentTime
|
|
let scheduleTimes = generateScheduleTimes currentTime 100 schedule
|
|
liftEitherM $ insertCronEvents $ map (CronEventSeed triggerName) scheduleTimes
|
|
|
|
-- | 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 ::
|
|
( MonadError QErr m,
|
|
CacheRWM m,
|
|
MonadIO m,
|
|
MetadataM m,
|
|
MonadMetadataStorage m
|
|
) =>
|
|
CreateCronTrigger ->
|
|
m EncJSON
|
|
runCreateCronTrigger CreateCronTrigger {..} = do
|
|
let q =
|
|
CronTriggerMetadata
|
|
_cctName
|
|
_cctWebhook
|
|
_cctCronSchedule
|
|
_cctPayload
|
|
_cctRetryConf
|
|
_cctHeaders
|
|
_cctIncludeInMetadata
|
|
_cctComment
|
|
_cctRequestTransform
|
|
_cctResponseTransform
|
|
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
|
|
_cctRequestTransform
|
|
_cctResponseTransform
|
|
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
|
|
let urlTemplate = printURLTemplate $ unInputWebhook ctWebhook
|
|
pure $
|
|
CronTriggerInfo
|
|
ctName
|
|
ctSchedule
|
|
ctPayload
|
|
ctRetryConf
|
|
(EnvRecord urlTemplate webhookInfo)
|
|
headerInfo
|
|
ctComment
|
|
ctRequestTransform
|
|
ctResponseTransform
|
|
|
|
updateCronTrigger ::
|
|
( MonadError QErr m,
|
|
CacheRWM m,
|
|
MonadIO m,
|
|
MetadataM m,
|
|
MonadMetadataStorage m
|
|
) =>
|
|
CronTriggerMetadata ->
|
|
m EncJSON
|
|
updateCronTrigger cronTriggerMetadata = do
|
|
let triggerName = ctName cronTriggerMetadata
|
|
checkExists triggerName
|
|
buildSchemaCacheFor (MOCronTrigger triggerName) $
|
|
MetadataModifier $
|
|
metaCronTriggers %~ OMap.insert triggerName cronTriggerMetadata
|
|
liftEitherM $ dropFutureCronEvents $ SingleCronTrigger triggerName
|
|
currentTime <- liftIO C.getCurrentTime
|
|
let scheduleTimes = generateScheduleTimes currentTime 100 $ ctSchedule cronTriggerMetadata
|
|
liftEitherM $ insertCronEvents $ map (CronEventSeed triggerName) scheduleTimes
|
|
pure successMsg
|
|
|
|
runDeleteCronTrigger ::
|
|
( MonadError QErr m,
|
|
CacheRWM m,
|
|
MetadataM m,
|
|
MonadMetadataStorage m
|
|
) =>
|
|
ScheduledTriggerName ->
|
|
m EncJSON
|
|
runDeleteCronTrigger (ScheduledTriggerName stName) = do
|
|
checkExists stName
|
|
withNewInconsistentObjsCheck $
|
|
buildSchemaCache $
|
|
dropCronTriggerInMetadata stName
|
|
liftEitherM $ dropFutureCronEvents $ SingleCronTrigger stName
|
|
return successMsg
|
|
|
|
dropCronTriggerInMetadata :: TriggerName -> MetadataModifier
|
|
dropCronTriggerInMetadata name =
|
|
MetadataModifier $ metaCronTriggers %~ OMap.delete name
|
|
|
|
runCreateScheduledEvent ::
|
|
(MonadError QErr m, MonadMetadataStorage m) =>
|
|
CreateScheduledEvent ->
|
|
m EncJSON
|
|
runCreateScheduledEvent scheduledEvent = do
|
|
eid <- liftEitherM $ 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 ::
|
|
(MonadMetadataStorage m, MonadError QErr m) => DeleteScheduledEvent -> m EncJSON
|
|
runDeleteScheduledEvent DeleteScheduledEvent {..} = do
|
|
liftEitherM $ dropEvent _dseEventId _dseType
|
|
pure successMsg
|
|
|
|
runGetScheduledEvents ::
|
|
( MonadError QErr m,
|
|
CacheRM m,
|
|
MonadMetadataStorage m
|
|
) =>
|
|
GetScheduledEvents ->
|
|
m EncJSON
|
|
runGetScheduledEvents gse = do
|
|
case _gseScheduledEvent gse of
|
|
SEOneOff -> pure ()
|
|
SECron name -> checkExists name
|
|
encJFromJValue <$> liftEitherM (fetchScheduledEvents gse)
|
|
|
|
runGetScheduledEventInvocations ::
|
|
( MonadError QErr m,
|
|
CacheRM m,
|
|
MonadMetadataStorage m
|
|
) =>
|
|
GetScheduledEventInvocations ->
|
|
m EncJSON
|
|
runGetScheduledEventInvocations getEventInvocations@GetScheduledEventInvocations {..} = do
|
|
case _geiInvocationsBy of
|
|
GIBEventId _ _ -> pure ()
|
|
GIBEvent event -> case event of
|
|
SEOneOff -> pure ()
|
|
SECron name -> checkExists name
|
|
WithOptionalTotalCount countMaybe invocations <- liftEitherM $ fetchScheduledEventInvocations getEventInvocations
|
|
pure $
|
|
encJFromJValue $
|
|
J.object $
|
|
("invocations" J..= invocations) : (maybe mempty (\count -> ["count" J..= count]) countMaybe)
|
|
|
|
-- | Metadata API handler to retrieve all the cron triggers from the metadata
|
|
runGetCronTriggers :: MetadataM m => m EncJSON
|
|
runGetCronTriggers = do
|
|
cronTriggers <- toList . _metaCronTriggers <$> getMetadata
|
|
pure $
|
|
encJFromJValue $
|
|
J.object
|
|
["cron_triggers" J..= cronTriggers]
|