retrier :: ( MonadCatch m
           , MonadResource m
           , MonadReader r m
           , HasEnv r
           , AWSRequest a
           )
        => a
        -> m (Either Error (Response a))
retrier x = do
    e  <- view environment
    rq <- configured x
    retrying (policy rq) (check e rq) (perform e rq)
  where
    policy rq = retryStream rq <> retryService (_rqService rq)

    check e rq n (Left r)
        | Just p <- r ^? transportErr, p = msg e "http_error" n >> return True
        | Just m <- r ^? serviceErr      = msg e m            n >> return True
      where
        transportErr = _TransportError . to (_envRetryCheck e n)
        serviceErr   = _ServiceError . to rc . _Just

        rc = rq ^. rqService . serviceRetry . retryCheck

    check _ _ _ _                          = return False

    msg :: MonadIO m => Env -> Text -> Int -> m ()
    msg e m n = logDebug (_envLogger e)
        . mconcat
        . intersperse " "
        $ [ "[Retry " <> build m <> "]"
          , "after"
          , build (n + 1)
          , "attempts."
          ]
retrier :: ( MonadCatch m
           , MonadResource m
           , MonadReader r m
           , HasEnv r
           , AWSRequest a
           )
        => a
        -> m (Either Error (Response a))
retrier x = do
    e  <- view environment
    rq <- configured x
    retrying (policy rq) (check e rq) (perform e rq)
  where
    policy rq = retryStream rq <> retryService (_rqService rq)

    check e rq n (Left r)
        | Just p <- r ^? transportErr, p = msg e "http_error" n >> return True
        | Just m <- r ^? serviceErr      = msg e m            n >> return True
      where
        transportErr = _TransportError . to (_envRetryCheck e n)
        serviceErr   = _ServiceError . to rc . _Just

        rc = rq ^. rqService . serviceRetry . retryCheck

    check _ _ _ _                          = return False

    msg :: MonadIO m => Env -> Text -> Int -> m ()
    msg e m n = logDebug (_envLogger e)
        . mconcat
        . intersperse " "
        $ [ "[Retry " <> build m <> "]"
          , "after"
          , build (n + 1)
          , "attempts."
          ]
retrier x = do
    e  <- view environment
    rq <- configured x
    retrying (policy rq) (check e rq) (perform e rq)
  where
    policy rq = retryStream rq <> retryService (_rqService rq)

    check e rq n (Left r)
        | Just p <- r ^? transportErr, p = msg e "http_error" n >> return True
        | Just m <- r ^? serviceErr      = msg e m            n >> return True
      where
        transportErr = _TransportError . to (_envRetryCheck e n)
        serviceErr   = _ServiceError . to rc . _Just

        rc = rq ^. rqService . serviceRetry . retryCheck

    check _ _ _ _                          = return False

    msg :: MonadIO m => Env -> Text -> Int -> m ()
    msg e m n = logDebug (_envLogger e)
        . mconcat
        . intersperse " "
        $ [ "[Retry " <> build m <> "]"
          , "after"
          , build (n + 1)
          , "attempts."
          ]