packages feed

faktory-1.1.3.1: library/Faktory/JobOptions.hs

{-# LANGUAGE DerivingVia #-}

module Faktory.JobOptions
  ( JobOptions (..)

    -- * Modifiers
  , retry
  , once
  , reserveFor
  , queue
  , jobtype
  , at
  , in_
  , custom

    -- * Enqueue-time modifiers
  , getAtFromSchedule
  , namespaceQueue
  ) where

import Faktory.Prelude

import Data.Aeson
import Data.Semigroup (Last (..))
import Data.Semigroup.Generic
import Data.Time
import Faktory.Job.Custom
import Faktory.Settings.Queue (Namespace, Queue)
import qualified Faktory.Settings.Queue as Settings
import GHC.Generics
import Numeric.Natural (Natural)

-- | Options for the execution of a job
--
-- These can be constructed using '(<>)':
--
-- @
-- let options = 'retry' 1 <> 'jobtype' "MyJob"
-- @
--
-- To enqueue with defaults, use 'mempty'.
--
-- Options use 'Last' semantics, so (e.g.) @'retry' x <>@ will set retries to
-- @x@ only if not already set, and @<> 'retry' x@ will override any
-- already-present retries to @x@.
data JobOptions = JobOptions
  { joJobtype :: Maybe (Last String)
  , joRetry :: Maybe (Last Int)
  , joQueue :: Maybe (Last Queue)
  , joSchedule :: Maybe (Last (Either UTCTime NominalDiffTime))
  , joCustom :: Maybe Custom
  , joReserveFor :: Maybe (Last Natural)
  }
  deriving stock (Eq, Show, Generic)
  deriving (Semigroup, Monoid) via GenericSemigroupMonoid JobOptions

instance FromJSON JobOptions where
  parseJSON = withObject "JobOptions" $ \o ->
    JobOptions
      <$> o .:? "jobtype"
      <*> o .:? "retry"
      <*> o .:? "queue"
      <*> (fmap (Last . Left) <$> o .:? "at")
      <*> o .:? "custom"
      <*> o .:? "reserve_for"

getAtFromSchedule :: JobOptions -> IO (Maybe UTCTime)
getAtFromSchedule options = for (getLast <$> joSchedule options) $ \case
  Left t -> pure t
  Right nd -> addUTCTime nd <$> getCurrentTime

namespaceQueue :: Namespace -> JobOptions -> JobOptions
namespaceQueue namespace options = case joQueue options of
  Nothing -> options
  Just (Last q) -> options <> queue (Settings.namespaceQueue namespace q)

reserveFor :: Natural -> JobOptions
reserveFor n = mempty {joReserveFor = Just $ Last n}

retry :: Int -> JobOptions
retry n = mempty {joRetry = Just $ Last n}

-- | Equivalent to @'retry' (-1)@: no retries, and move to Dead on failure
once :: JobOptions
once = retry (-1)

queue :: Queue -> JobOptions
queue q = mempty {joQueue = Just $ Last q}

jobtype :: String -> JobOptions
jobtype jt = mempty {joJobtype = Just $ Last jt}

at :: UTCTime -> JobOptions
at t = mempty {joSchedule = Just $ Last $ Left t}

in_ :: NominalDiffTime -> JobOptions
in_ i = mempty {joSchedule = Just $ Last $ Right i}

custom :: ToJSON a => a -> JobOptions
custom v = mempty {joCustom = Just $ toCustom v}