packages feed

faktory-1.0.2.1: library/Faktory/JobOptions.hs

{-# LANGUAGE DerivingVia #-}

module Faktory.JobOptions
  ( JobOptions(..)

  -- * Modifiers
  , retry
  , once
  , 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 (Namespace, Queue)
import qualified Faktory.Settings as Settings
import GHC.Generics

-- | 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
  }
  deriving stock Generic
  deriving (Semigroup, Monoid) via GenericSemigroupMonoid JobOptions

-- brittany-disable-next-binding

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

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)

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 }