{-# LANGUAGE OverloadedStrings #-}

-- | Exceptions thrown by job handlers and by the worker engine.
--
-- 'JobException' selects retry, DLQ, or tree\/branch cancellation.
-- 'JobNackException' requests reprocessing without a recorded failure.
-- Engine signals use separate exception types.
module Arbiter.Core.Exceptions
  ( -- * User-facing job decisions
    JobException (..)
  , JobRetryableException (..)
  , JobPermanentException (..)
  , TreeCancelException (..)
  , BranchCancelException (..)
  , JobNackException (..)

    -- * Engine-internal signals
  , ParsingException (..)
  , InternalException (..)
  , JobGoneException (..)
  , JobScopedFailure (..)
  , JobForceCancelled (..)
  , JobDeadlineExceeded (..)

    -- * Helpers
  , throwRetryable
  , throwRetryableAfter
  , throwPermanent
  , throwTreeCancel
  , throwBranchCancel
  , throwNack
  , throwNackAfter

    -- * Internal

    -- | Internal to the arbiter packages. Not covered by the PVP.
  , throwParsing
  , orThrowParsing
  , throwInternal
  , orThrowInternal
  , throwJobGone
  , throwJobGoneIds
  , throwScopedFailure
  , namedJobIds
  , displayEx
  ) where

import Control.Exception (Exception (..), SomeException (..), asyncExceptionFromException, asyncExceptionToException)
import Control.Monad.IO.Class (MonadIO)
import Data.Int (Int64)
import Data.Text (Text)
import Data.Text qualified as T
import Data.Time (NominalDiffTime)
import GHC.Generics (Generic)
import UnliftIO.Exception qualified as UE

import Arbiter.Core.Enum (showText)

-- | Decisions a handler can signal by throwing. The worker catches it and retries,
-- dead-letters or cancels the job.
data JobException
  = -- | Retries the job after its delay, or with backoff.
    Retryable JobRetryableException
  | -- | Moves the job to the DLQ.
    Permanent JobPermanentException
  | -- | Deletes the entire job tree from root to leaves.
    TreeCancel TreeCancelException
  | -- | Cancels the parent and every descendant. A job with no parent cancels only
    -- itself and its descendants.
    BranchCancel BranchCancelException
  deriving stock (Int -> JobException -> ShowS
[JobException] -> ShowS
JobException -> String
(Int -> JobException -> ShowS)
-> (JobException -> String)
-> ([JobException] -> ShowS)
-> Show JobException
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> JobException -> ShowS
showsPrec :: Int -> JobException -> ShowS
$cshow :: JobException -> String
show :: JobException -> String
$cshowList :: [JobException] -> ShowS
showList :: [JobException] -> ShowS
Show)

instance Exception JobException where
  backtraceDesired :: JobException -> Bool
backtraceDesired JobException
_ = Bool
False
  displayException :: JobException -> String
displayException = \case
    Retryable JobRetryableException
inner -> JobRetryableException -> String
forall e. Exception e => e -> String
displayException JobRetryableException
inner
    Permanent JobPermanentException
inner -> JobPermanentException -> String
forall e. Exception e => e -> String
displayException JobPermanentException
inner
    TreeCancel TreeCancelException
inner -> TreeCancelException -> String
forall e. Exception e => e -> String
displayException TreeCancelException
inner
    BranchCancel BranchCancelException
inner -> BranchCancelException -> String
forall e. Exception e => e -> String
displayException BranchCancelException
inner

-- | Transient failure. The job is retried after the delay in seconds, or with the
-- pool's backoff when there is none.
data JobRetryableException = JobRetryableException Text (Maybe NominalDiffTime)
  deriving stock (JobRetryableException -> JobRetryableException -> Bool
(JobRetryableException -> JobRetryableException -> Bool)
-> (JobRetryableException -> JobRetryableException -> Bool)
-> Eq JobRetryableException
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: JobRetryableException -> JobRetryableException -> Bool
== :: JobRetryableException -> JobRetryableException -> Bool
$c/= :: JobRetryableException -> JobRetryableException -> Bool
/= :: JobRetryableException -> JobRetryableException -> Bool
Eq, (forall x. JobRetryableException -> Rep JobRetryableException x)
-> (forall x. Rep JobRetryableException x -> JobRetryableException)
-> Generic JobRetryableException
forall x. Rep JobRetryableException x -> JobRetryableException
forall x. JobRetryableException -> Rep JobRetryableException x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cfrom :: forall x. JobRetryableException -> Rep JobRetryableException x
from :: forall x. JobRetryableException -> Rep JobRetryableException x
$cto :: forall x. Rep JobRetryableException x -> JobRetryableException
to :: forall x. Rep JobRetryableException x -> JobRetryableException
Generic, Int -> JobRetryableException -> ShowS
[JobRetryableException] -> ShowS
JobRetryableException -> String
(Int -> JobRetryableException -> ShowS)
-> (JobRetryableException -> String)
-> ([JobRetryableException] -> ShowS)
-> Show JobRetryableException
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> JobRetryableException -> ShowS
showsPrec :: Int -> JobRetryableException -> ShowS
$cshow :: JobRetryableException -> String
show :: JobRetryableException -> String
$cshowList :: [JobRetryableException] -> ShowS
showList :: [JobRetryableException] -> ShowS
Show)

instance Exception JobRetryableException where
  displayException :: JobRetryableException -> String
displayException (JobRetryableException Text
msg Maybe NominalDiffTime
_) = Text -> String
T.unpack Text
msg

-- | Permanent failure. The job goes straight to the DLQ.
newtype JobPermanentException = JobPermanentException Text
  deriving stock (JobPermanentException -> JobPermanentException -> Bool
(JobPermanentException -> JobPermanentException -> Bool)
-> (JobPermanentException -> JobPermanentException -> Bool)
-> Eq JobPermanentException
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: JobPermanentException -> JobPermanentException -> Bool
== :: JobPermanentException -> JobPermanentException -> Bool
$c/= :: JobPermanentException -> JobPermanentException -> Bool
/= :: JobPermanentException -> JobPermanentException -> Bool
Eq, (forall x. JobPermanentException -> Rep JobPermanentException x)
-> (forall x. Rep JobPermanentException x -> JobPermanentException)
-> Generic JobPermanentException
forall x. Rep JobPermanentException x -> JobPermanentException
forall x. JobPermanentException -> Rep JobPermanentException x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cfrom :: forall x. JobPermanentException -> Rep JobPermanentException x
from :: forall x. JobPermanentException -> Rep JobPermanentException x
$cto :: forall x. Rep JobPermanentException x -> JobPermanentException
to :: forall x. Rep JobPermanentException x -> JobPermanentException
Generic, Int -> JobPermanentException -> ShowS
[JobPermanentException] -> ShowS
JobPermanentException -> String
(Int -> JobPermanentException -> ShowS)
-> (JobPermanentException -> String)
-> ([JobPermanentException] -> ShowS)
-> Show JobPermanentException
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> JobPermanentException -> ShowS
showsPrec :: Int -> JobPermanentException -> ShowS
$cshow :: JobPermanentException -> String
show :: JobPermanentException -> String
$cshowList :: [JobPermanentException] -> ShowS
showList :: [JobPermanentException] -> ShowS
Show)

instance Exception JobPermanentException where
  displayException :: JobPermanentException -> String
displayException (JobPermanentException Text
msg) = Text -> String
T.unpack Text
msg

-- | Cancel the whole job tree, root to leaves.
newtype TreeCancelException = TreeCancelException Text
  deriving stock (TreeCancelException -> TreeCancelException -> Bool
(TreeCancelException -> TreeCancelException -> Bool)
-> (TreeCancelException -> TreeCancelException -> Bool)
-> Eq TreeCancelException
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: TreeCancelException -> TreeCancelException -> Bool
== :: TreeCancelException -> TreeCancelException -> Bool
$c/= :: TreeCancelException -> TreeCancelException -> Bool
/= :: TreeCancelException -> TreeCancelException -> Bool
Eq, (forall x. TreeCancelException -> Rep TreeCancelException x)
-> (forall x. Rep TreeCancelException x -> TreeCancelException)
-> Generic TreeCancelException
forall x. Rep TreeCancelException x -> TreeCancelException
forall x. TreeCancelException -> Rep TreeCancelException x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cfrom :: forall x. TreeCancelException -> Rep TreeCancelException x
from :: forall x. TreeCancelException -> Rep TreeCancelException x
$cto :: forall x. Rep TreeCancelException x -> TreeCancelException
to :: forall x. Rep TreeCancelException x -> TreeCancelException
Generic, Int -> TreeCancelException -> ShowS
[TreeCancelException] -> ShowS
TreeCancelException -> String
(Int -> TreeCancelException -> ShowS)
-> (TreeCancelException -> String)
-> ([TreeCancelException] -> ShowS)
-> Show TreeCancelException
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> TreeCancelException -> ShowS
showsPrec :: Int -> TreeCancelException -> ShowS
$cshow :: TreeCancelException -> String
show :: TreeCancelException -> String
$cshowList :: [TreeCancelException] -> ShowS
showList :: [TreeCancelException] -> ShowS
Show)

instance Exception TreeCancelException where
  displayException :: TreeCancelException -> String
displayException (TreeCancelException Text
msg) = Text -> String
T.unpack Text
msg

-- | Cancel the parent and every descendant. A job with no parent cancels only itself
-- and its descendants. A grandparent above is resumed.
newtype BranchCancelException = BranchCancelException Text
  deriving stock (BranchCancelException -> BranchCancelException -> Bool
(BranchCancelException -> BranchCancelException -> Bool)
-> (BranchCancelException -> BranchCancelException -> Bool)
-> Eq BranchCancelException
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: BranchCancelException -> BranchCancelException -> Bool
== :: BranchCancelException -> BranchCancelException -> Bool
$c/= :: BranchCancelException -> BranchCancelException -> Bool
/= :: BranchCancelException -> BranchCancelException -> Bool
Eq, (forall x. BranchCancelException -> Rep BranchCancelException x)
-> (forall x. Rep BranchCancelException x -> BranchCancelException)
-> Generic BranchCancelException
forall x. Rep BranchCancelException x -> BranchCancelException
forall x. BranchCancelException -> Rep BranchCancelException x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cfrom :: forall x. BranchCancelException -> Rep BranchCancelException x
from :: forall x. BranchCancelException -> Rep BranchCancelException x
$cto :: forall x. Rep BranchCancelException x -> BranchCancelException
to :: forall x. Rep BranchCancelException x -> BranchCancelException
Generic, Int -> BranchCancelException -> ShowS
[BranchCancelException] -> ShowS
BranchCancelException -> String
(Int -> BranchCancelException -> ShowS)
-> (BranchCancelException -> String)
-> ([BranchCancelException] -> ShowS)
-> Show BranchCancelException
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> BranchCancelException -> ShowS
showsPrec :: Int -> BranchCancelException -> ShowS
$cshow :: BranchCancelException -> String
show :: BranchCancelException -> String
$cshowList :: [BranchCancelException] -> ShowS
showList :: [BranchCancelException] -> ShowS
Show)

instance Exception BranchCancelException where
  displayException :: BranchCancelException -> String
displayException (BranchCancelException Text
msg) = Text -> String
T.unpack Text
msg

-- | Reprocess the job later without recording a failure (a soft nack). The
-- worker skips retry\/DLQ, hands back the attempt the claim consumed, and leaves
-- the job to become visible again after the delay in seconds, or when its lease
-- lapses when there is none.
newtype JobNackException = JobNackException (Maybe NominalDiffTime)
  deriving stock (JobNackException -> JobNackException -> Bool
(JobNackException -> JobNackException -> Bool)
-> (JobNackException -> JobNackException -> Bool)
-> Eq JobNackException
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: JobNackException -> JobNackException -> Bool
== :: JobNackException -> JobNackException -> Bool
$c/= :: JobNackException -> JobNackException -> Bool
/= :: JobNackException -> JobNackException -> Bool
Eq, (forall x. JobNackException -> Rep JobNackException x)
-> (forall x. Rep JobNackException x -> JobNackException)
-> Generic JobNackException
forall x. Rep JobNackException x -> JobNackException
forall x. JobNackException -> Rep JobNackException x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cfrom :: forall x. JobNackException -> Rep JobNackException x
from :: forall x. JobNackException -> Rep JobNackException x
$cto :: forall x. Rep JobNackException x -> JobNackException
to :: forall x. Rep JobNackException x -> JobNackException
Generic, Int -> JobNackException -> ShowS
[JobNackException] -> ShowS
JobNackException -> String
(Int -> JobNackException -> ShowS)
-> (JobNackException -> String)
-> ([JobNackException] -> ShowS)
-> Show JobNackException
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> JobNackException -> ShowS
showsPrec :: Int -> JobNackException -> ShowS
$cshow :: JobNackException -> String
show :: JobNackException -> String
$cshowList :: [JobNackException] -> ShowS
showList :: [JobNackException] -> ShowS
Show)

instance Exception JobNackException where
  backtraceDesired :: JobNackException -> Bool
backtraceDesired JobNackException
_ = Bool
False
  displayException :: JobNackException -> String
displayException (JobNackException Maybe NominalDiffTime
_) = String
"job nacked for reprocessing"

-- | Row decoding failure (engine-internal). Classified as a permanent failure
-- by the worker.
newtype ParsingException = ParsingException Text
  deriving stock (ParsingException -> ParsingException -> Bool
(ParsingException -> ParsingException -> Bool)
-> (ParsingException -> ParsingException -> Bool)
-> Eq ParsingException
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: ParsingException -> ParsingException -> Bool
== :: ParsingException -> ParsingException -> Bool
$c/= :: ParsingException -> ParsingException -> Bool
/= :: ParsingException -> ParsingException -> Bool
Eq, (forall x. ParsingException -> Rep ParsingException x)
-> (forall x. Rep ParsingException x -> ParsingException)
-> Generic ParsingException
forall x. Rep ParsingException x -> ParsingException
forall x. ParsingException -> Rep ParsingException x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cfrom :: forall x. ParsingException -> Rep ParsingException x
from :: forall x. ParsingException -> Rep ParsingException x
$cto :: forall x. Rep ParsingException x -> ParsingException
to :: forall x. Rep ParsingException x -> ParsingException
Generic, Int -> ParsingException -> ShowS
[ParsingException] -> ShowS
ParsingException -> String
(Int -> ParsingException -> ShowS)
-> (ParsingException -> String)
-> ([ParsingException] -> ShowS)
-> Show ParsingException
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> ParsingException -> ShowS
showsPrec :: Int -> ParsingException -> ShowS
$cshow :: ParsingException -> String
show :: ParsingException -> String
$cshowList :: [ParsingException] -> ShowS
showList :: [ParsingException] -> ShowS
Show)

instance Exception ParsingException where
  displayException :: ParsingException -> String
displayException (ParsingException Text
msg) = Text -> String
T.unpack Text
msg

-- | Generic engine-internal failure, such as a missing connection or bad parameters.
newtype InternalException = InternalException Text
  deriving stock (InternalException -> InternalException -> Bool
(InternalException -> InternalException -> Bool)
-> (InternalException -> InternalException -> Bool)
-> Eq InternalException
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: InternalException -> InternalException -> Bool
== :: InternalException -> InternalException -> Bool
$c/= :: InternalException -> InternalException -> Bool
/= :: InternalException -> InternalException -> Bool
Eq, (forall x. InternalException -> Rep InternalException x)
-> (forall x. Rep InternalException x -> InternalException)
-> Generic InternalException
forall x. Rep InternalException x -> InternalException
forall x. InternalException -> Rep InternalException x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cfrom :: forall x. InternalException -> Rep InternalException x
from :: forall x. InternalException -> Rep InternalException x
$cto :: forall x. Rep InternalException x -> InternalException
to :: forall x. Rep InternalException x -> InternalException
Generic, Int -> InternalException -> ShowS
[InternalException] -> ShowS
InternalException -> String
(Int -> InternalException -> ShowS)
-> (InternalException -> String)
-> ([InternalException] -> ShowS)
-> Show InternalException
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> InternalException -> ShowS
showsPrec :: Int -> InternalException -> ShowS
$cshow :: InternalException -> String
show :: InternalException -> String
$cshowList :: [InternalException] -> ShowS
showList :: [InternalException] -> ShowS
Show)

instance Exception InternalException where
  displayException :: InternalException -> String
displayException (InternalException Text
msg) = Text -> String
T.unpack Text
msg

-- | Job was deleted or reclaimed between claim and ack. The worker recognizes this
-- signal and skips retry\/DLQ. The message is the reason reported to
-- 'Arbiter.Core.Job.Types.onJobUnavailable'. The ids are the jobs that are gone.
-- Empty when the thrower did not name them.
data JobGoneException = JobGoneException Text [Int64]
  deriving stock (JobGoneException -> JobGoneException -> Bool
(JobGoneException -> JobGoneException -> Bool)
-> (JobGoneException -> JobGoneException -> Bool)
-> Eq JobGoneException
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: JobGoneException -> JobGoneException -> Bool
== :: JobGoneException -> JobGoneException -> Bool
$c/= :: JobGoneException -> JobGoneException -> Bool
/= :: JobGoneException -> JobGoneException -> Bool
Eq, (forall x. JobGoneException -> Rep JobGoneException x)
-> (forall x. Rep JobGoneException x -> JobGoneException)
-> Generic JobGoneException
forall x. Rep JobGoneException x -> JobGoneException
forall x. JobGoneException -> Rep JobGoneException x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cfrom :: forall x. JobGoneException -> Rep JobGoneException x
from :: forall x. JobGoneException -> Rep JobGoneException x
$cto :: forall x. Rep JobGoneException x -> JobGoneException
to :: forall x. Rep JobGoneException x -> JobGoneException
Generic, Int -> JobGoneException -> ShowS
[JobGoneException] -> ShowS
JobGoneException -> String
(Int -> JobGoneException -> ShowS)
-> (JobGoneException -> String)
-> ([JobGoneException] -> ShowS)
-> Show JobGoneException
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> JobGoneException -> ShowS
showsPrec :: Int -> JobGoneException -> ShowS
$cshow :: JobGoneException -> String
show :: JobGoneException -> String
$cshowList :: [JobGoneException] -> ShowS
showList :: [JobGoneException] -> ShowS
Show)

instance Exception JobGoneException where
  backtraceDesired :: JobGoneException -> Bool
backtraceDesired JobGoneException
_ = Bool
False
  displayException :: JobGoneException -> String
displayException (JobGoneException Text
msg [Int64]
ids) = Text -> String
T.unpack (Text
msg Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> [Int64] -> Text
namedJobIds [Int64]
ids)

-- | A failure that settles the jobs it names and no others.
data JobScopedFailure = JobScopedFailure JobException [Int64]
  deriving stock (Int -> JobScopedFailure -> ShowS
[JobScopedFailure] -> ShowS
JobScopedFailure -> String
(Int -> JobScopedFailure -> ShowS)
-> (JobScopedFailure -> String)
-> ([JobScopedFailure] -> ShowS)
-> Show JobScopedFailure
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> JobScopedFailure -> ShowS
showsPrec :: Int -> JobScopedFailure -> ShowS
$cshow :: JobScopedFailure -> String
show :: JobScopedFailure -> String
$cshowList :: [JobScopedFailure] -> ShowS
showList :: [JobScopedFailure] -> ShowS
Show)

instance Exception JobScopedFailure where
  backtraceDesired :: JobScopedFailure -> Bool
backtraceDesired JobScopedFailure
_ = Bool
False
  displayException :: JobScopedFailure -> String
displayException (JobScopedFailure JobException
inner [Int64]
ids) = JobException -> String
forall e. Exception e => e -> String
displayException JobException
inner String -> ShowS
forall a. Semigroup a => a -> a -> a
<> Text -> String
T.unpack ([Int64] -> Text
namedJobIds [Int64]
ids)

-- | Async exception for an operator force-cancel. Names the cancelled jobs, then the
-- jobs the same check found reclaimed or gone.
data JobForceCancelled = JobForceCancelled [Int64] [Int64]
  deriving stock (Int -> JobForceCancelled -> ShowS
[JobForceCancelled] -> ShowS
JobForceCancelled -> String
(Int -> JobForceCancelled -> ShowS)
-> (JobForceCancelled -> String)
-> ([JobForceCancelled] -> ShowS)
-> Show JobForceCancelled
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> JobForceCancelled -> ShowS
showsPrec :: Int -> JobForceCancelled -> ShowS
$cshow :: JobForceCancelled -> String
show :: JobForceCancelled -> String
$cshowList :: [JobForceCancelled] -> ShowS
showList :: [JobForceCancelled] -> ShowS
Show)

instance Exception JobForceCancelled where
  backtraceDesired :: JobForceCancelled -> Bool
backtraceDesired JobForceCancelled
_ = Bool
False
  toException :: JobForceCancelled -> SomeException
toException = JobForceCancelled -> SomeException
forall e. Exception e => e -> SomeException
asyncExceptionToException
  fromException :: SomeException -> Maybe JobForceCancelled
fromException = SomeException -> Maybe JobForceCancelled
forall e. Exception e => SomeException -> Maybe e
asyncExceptionFromException
  displayException :: JobForceCancelled -> String
displayException (JobForceCancelled [Int64]
cancelled [Int64]
gone) =
    Text -> String
T.unpack (Text
"job force-cancelled" Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> [Int64] -> Text
namedJobIds [Int64]
cancelled Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
goneNamed)
    where
      goneNamed :: Text
goneNamed
        | [Int64] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [Int64]
gone = Text
""
        | Bool
otherwise = Text
" (reclaimed or gone" Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> [Int64] -> Text
namedJobIds [Int64]
gone Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
")"

-- | A batch's claim hooks and handler ran past the pool's maximum job duration. Classified as a retryable failure.
newtype JobDeadlineExceeded = JobDeadlineExceeded Text
  deriving stock (JobDeadlineExceeded -> JobDeadlineExceeded -> Bool
(JobDeadlineExceeded -> JobDeadlineExceeded -> Bool)
-> (JobDeadlineExceeded -> JobDeadlineExceeded -> Bool)
-> Eq JobDeadlineExceeded
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: JobDeadlineExceeded -> JobDeadlineExceeded -> Bool
== :: JobDeadlineExceeded -> JobDeadlineExceeded -> Bool
$c/= :: JobDeadlineExceeded -> JobDeadlineExceeded -> Bool
/= :: JobDeadlineExceeded -> JobDeadlineExceeded -> Bool
Eq, (forall x. JobDeadlineExceeded -> Rep JobDeadlineExceeded x)
-> (forall x. Rep JobDeadlineExceeded x -> JobDeadlineExceeded)
-> Generic JobDeadlineExceeded
forall x. Rep JobDeadlineExceeded x -> JobDeadlineExceeded
forall x. JobDeadlineExceeded -> Rep JobDeadlineExceeded x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cfrom :: forall x. JobDeadlineExceeded -> Rep JobDeadlineExceeded x
from :: forall x. JobDeadlineExceeded -> Rep JobDeadlineExceeded x
$cto :: forall x. Rep JobDeadlineExceeded x -> JobDeadlineExceeded
to :: forall x. Rep JobDeadlineExceeded x -> JobDeadlineExceeded
Generic, Int -> JobDeadlineExceeded -> ShowS
[JobDeadlineExceeded] -> ShowS
JobDeadlineExceeded -> String
(Int -> JobDeadlineExceeded -> ShowS)
-> (JobDeadlineExceeded -> String)
-> ([JobDeadlineExceeded] -> ShowS)
-> Show JobDeadlineExceeded
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> JobDeadlineExceeded -> ShowS
showsPrec :: Int -> JobDeadlineExceeded -> ShowS
$cshow :: JobDeadlineExceeded -> String
show :: JobDeadlineExceeded -> String
$cshowList :: [JobDeadlineExceeded] -> ShowS
showList :: [JobDeadlineExceeded] -> ShowS
Show)

instance Exception JobDeadlineExceeded where
  backtraceDesired :: JobDeadlineExceeded -> Bool
backtraceDesired JobDeadlineExceeded
_ = Bool
False
  displayException :: JobDeadlineExceeded -> String
displayException (JobDeadlineExceeded Text
msg) = Text -> String
T.unpack Text
msg

-- | Fail the job and let it retry.
throwRetryable :: (MonadIO m) => Text -> m a
throwRetryable :: forall (m :: * -> *) a. MonadIO m => Text -> m a
throwRetryable Text
msg = JobException -> m a
forall (m :: * -> *) e a. (MonadIO m, Exception e) => e -> m a
UE.throwIO (JobRetryableException -> JobException
Retryable (Text -> Maybe NominalDiffTime -> JobRetryableException
JobRetryableException Text
msg Maybe NominalDiffTime
forall a. Maybe a
Nothing))

-- | Fail the job and retry it after a delay in seconds, in place of the pool's backoff.
-- The failure uses an attempt.
throwRetryableAfter :: (MonadIO m) => NominalDiffTime -> Text -> m a
throwRetryableAfter :: forall (m :: * -> *) a. MonadIO m => NominalDiffTime -> Text -> m a
throwRetryableAfter NominalDiffTime
delay Text
msg = JobException -> m a
forall (m :: * -> *) e a. (MonadIO m, Exception e) => e -> m a
UE.throwIO (JobRetryableException -> JobException
Retryable (Text -> Maybe NominalDiffTime -> JobRetryableException
JobRetryableException Text
msg (NominalDiffTime -> Maybe NominalDiffTime
forall a. a -> Maybe a
Just NominalDiffTime
delay)))

-- | Fail the job straight to the DLQ.
throwPermanent :: (MonadIO m) => Text -> m a
throwPermanent :: forall (m :: * -> *) a. MonadIO m => Text -> m a
throwPermanent Text
msg = JobException -> m a
forall (m :: * -> *) e a. (MonadIO m, Exception e) => e -> m a
UE.throwIO (JobPermanentException -> JobException
Permanent (Text -> JobPermanentException
JobPermanentException Text
msg))

-- | Cancel the whole job tree.
throwTreeCancel :: (MonadIO m) => Text -> m a
throwTreeCancel :: forall (m :: * -> *) a. MonadIO m => Text -> m a
throwTreeCancel Text
msg = JobException -> m a
forall (m :: * -> *) e a. (MonadIO m, Exception e) => e -> m a
UE.throwIO (TreeCancelException -> JobException
TreeCancel (Text -> TreeCancelException
TreeCancelException Text
msg))

-- | Cancel the parent and every descendant. A job with no parent cancels only itself
-- and its descendants.
throwBranchCancel :: (MonadIO m) => Text -> m a
throwBranchCancel :: forall (m :: * -> *) a. MonadIO m => Text -> m a
throwBranchCancel Text
msg = JobException -> m a
forall (m :: * -> *) e a. (MonadIO m, Exception e) => e -> m a
UE.throwIO (BranchCancelException -> JobException
BranchCancel (Text -> BranchCancelException
BranchCancelException Text
msg))

-- | Return the job to the queue without consuming an attempt.
throwNack :: (MonadIO m) => m a
throwNack :: forall (m :: * -> *) a. MonadIO m => m a
throwNack = JobNackException -> m a
forall (m :: * -> *) e a. (MonadIO m, Exception e) => e -> m a
UE.throwIO (Maybe NominalDiffTime -> JobNackException
JobNackException Maybe NominalDiffTime
forall a. Maybe a
Nothing)

-- | Return the job to the queue without consuming an attempt, visible again after a
-- delay in seconds.
throwNackAfter :: (MonadIO m) => NominalDiffTime -> m a
throwNackAfter :: forall (m :: * -> *) a. MonadIO m => NominalDiffTime -> m a
throwNackAfter NominalDiffTime
delay = JobNackException -> m a
forall (m :: * -> *) e a. (MonadIO m, Exception e) => e -> m a
UE.throwIO (Maybe NominalDiffTime -> JobNackException
JobNackException (NominalDiffTime -> Maybe NominalDiffTime
forall a. a -> Maybe a
Just NominalDiffTime
delay))

-- | Fail on an undecodable payload.
throwParsing :: (MonadIO m) => Text -> m a
throwParsing :: forall (m :: * -> *) a. MonadIO m => Text -> m a
throwParsing Text
msg = ParsingException -> m a
forall (m :: * -> *) e a. (MonadIO m, Exception e) => e -> m a
UE.throwIO (Text -> ParsingException
ParsingException Text
msg)

-- | The 'Right' value, or 'throwParsing' on the 'Left' message.
orThrowParsing :: (MonadIO m) => Either Text a -> m a
orThrowParsing :: forall (m :: * -> *) a. MonadIO m => Either Text a -> m a
orThrowParsing = (Text -> m a) -> (a -> m a) -> Either Text a -> m a
forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either Text -> m a
forall (m :: * -> *) a. MonadIO m => Text -> m a
throwParsing a -> m a
forall a. a -> m a
forall (f :: * -> *) a. Applicative f => a -> f a
pure

-- | Fail on an arbiter-internal error.
throwInternal :: (MonadIO m) => Text -> m a
throwInternal :: forall (m :: * -> *) a. MonadIO m => Text -> m a
throwInternal Text
msg = InternalException -> m a
forall (m :: * -> *) e a. (MonadIO m, Exception e) => e -> m a
UE.throwIO (Text -> InternalException
InternalException Text
msg)

-- | The 'Right' value, or 'throwInternal' on the rendered 'Left'.
orThrowInternal :: (MonadIO m) => (e -> Text) -> Either e a -> m a
orThrowInternal :: forall (m :: * -> *) e a.
MonadIO m =>
(e -> Text) -> Either e a -> m a
orThrowInternal e -> Text
render = (e -> m a) -> (a -> m a) -> Either e a -> m a
forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either (Text -> m a
forall (m :: * -> *) a. MonadIO m => Text -> m a
throwInternal (Text -> m a) -> (e -> Text) -> e -> m a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. e -> Text
render) a -> m a
forall a. a -> m a
forall (f :: * -> *) a. Applicative f => a -> f a
pure

-- | Throw 'JobGoneException' naming the jobs that went away.
throwJobGoneIds :: (MonadIO m) => Text -> [Int64] -> m a
throwJobGoneIds :: forall (m :: * -> *) a. MonadIO m => Text -> [Int64] -> m a
throwJobGoneIds Text
msg [Int64]
ids = JobGoneException -> m a
forall (m :: * -> *) e a. (MonadIO m, Exception e) => e -> m a
UE.throwIO (Text -> [Int64] -> JobGoneException
JobGoneException Text
msg [Int64]
ids)

-- | Signal that the claim is no longer valid, naming no ids.
throwJobGone :: (MonadIO m) => Text -> m a
throwJobGone :: forall (m :: * -> *) a. MonadIO m => Text -> m a
throwJobGone Text
msg = Text -> [Int64] -> m a
forall (m :: * -> *) a. MonadIO m => Text -> [Int64] -> m a
throwJobGoneIds Text
msg []

-- | Fail only the jobs named, leaving the rest of the batch its attempt.
throwScopedFailure :: (MonadIO m) => JobException -> [Int64] -> m a
throwScopedFailure :: forall (m :: * -> *) a. MonadIO m => JobException -> [Int64] -> m a
throwScopedFailure JobException
inner [Int64]
ids = JobScopedFailure -> m a
forall (m :: * -> *) e a. (MonadIO m, Exception e) => e -> m a
UE.throwIO (JobException -> [Int64] -> JobScopedFailure
JobScopedFailure JobException
inner [Int64]
ids)

-- | The ids a signal names, appended to its message. Empty when it names none.
namedJobIds :: [Int64] -> Text
namedJobIds :: [Int64] -> Text
namedJobIds [] = Text
""
namedJobIds [Int64]
ids = Text
": " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text -> [Text] -> Text
T.intercalate Text
", " ((Int64 -> Text) -> [Int64] -> [Text]
forall a b. (a -> b) -> [a] -> [b]
map Int64 -> Text
forall a. Show a => a -> Text
showText [Int64]
ids)

-- | An exception's inner message. It carries no backtrace.
displayEx :: SomeException -> Text
displayEx :: SomeException -> Text
displayEx (SomeException e
inner) = String -> Text
T.pack (e -> String
forall e. Exception e => e -> String
displayException e
inner)