stamina.hs/README.md

77 lines
2.5 KiB
Markdown
Raw Normal View History

2023-07-05 17:21:33 +03:00
# Stamina
2023-07-04 17:36:38 +03:00
2023-12-30 18:14:51 +03:00
[![Active The project has reached a stable, usable state and is being actively developed.](https://www.repostatus.org/badges/latest/active.svg)](https://www.repostatus.org/#concept) [![Hackage](https://img.shields.io/hackage/v/stamina.svg?style=flat)](https://hackage.haskell.org/package/stamina) ![CI status](https://github.com/cachix/stamina.hs/actions/workflows/ci.yml/badge.svg)
2023-07-04 18:46:57 +03:00
2023-07-05 17:14:19 +03:00
A retry Haskell library for humans:
2023-07-05 17:18:27 +03:00
- **Exponential backoff** with **jitter** between retries.
- Limit the **attempts** of retries and **total** time.
2023-12-30 18:14:51 +03:00
- `Stamina.HTTP` for retrying retriable `Network.HTTP.Client` exceptions respecting `Retry-After` headers.
- Introspectable retry state for logging using `RetryStatus`, including the last exception that occurred.
- Support resetting the retry state when the action is long-running with an attempt that works.
2023-07-04 18:46:57 +03:00
2023-07-05 17:14:19 +03:00
## API
2023-12-30 18:14:51 +03:00
## Basics
2023-07-05 17:14:19 +03:00
2023-12-30 18:14:51 +03:00
- `Stamina.defaults :: (MonadIO m) => m RetrySettings`
- `Stamina.RetryStatus = RetryStatus { attempts :: Int, delay :: NominalDiffTime, totalDelay :: NominalDiffTime, resetInitial :: IO (), lastException :: Maybe SomeException }`
- `Stamina.retry :: (MonadCatch m, MonadIO m) => RetrySettings -> (RetryStatus -> m a) -> m a`
## Exceptions
- `Stamina.RetryAction = RaiseException | Retry | RetryDelay NominalDiffTime | RetryTime UTCTime`
- `Stamina.retryFor :: (MonadCatch m, MonadIO m, Exception exc) => RetrySettings -> (exc -> m RetryAction) -> (RetryStatus -> m a) -> m a`
## HTTP
- `Stamina.HTPP.retry :: (MonadIO m, MonadCatch m) => Stamina.RetrySettings -> (Stamina.RetryStatus -> m a) -> m a`
## Basic example
2023-07-05 17:14:19 +03:00
```haskell
import qualified Stamina
2023-12-30 14:38:00 +03:00
import Control.Monad.Catch (throwM)
2023-12-30 18:00:07 +03:00
import Control.Monad.IO.Class (MonadIO)
2023-07-05 17:14:19 +03:00
2023-12-30 14:38:00 +03:00
go :: IO ()
go = do
defaults <- Stamina.defaults
Stamina.retry defaults $ \retryStatus -> do
throwM $ userError "nope"
```
## Example to catch specific exceptions
2023-07-05 17:14:19 +03:00
2023-12-30 14:38:00 +03:00
```haskell
2023-12-30 18:00:07 +03:00
handler :: (MonadIO m) => IOError -> m Stamina.RetryAction
handler _ = return Stamina.Retry
2023-12-30 14:38:00 +03:00
go2 :: IO ()
go2 = do
defaults <- Stamina.defaults
2023-12-30 18:03:11 +03:00
Stamina.retryFor defaults handler $ \retryStatus -> do
2023-12-30 14:38:00 +03:00
throwM $ userError "nope"
2023-07-05 17:14:19 +03:00
```
2023-07-04 18:46:57 +03:00
## Development
1. Install [devenv.sh](https://devenv.sh/getting-started/).
2. `devenv shell`
2023-07-05 17:14:19 +03:00
3. `stack build`
## Credits
- Heavily inspired by [stamina for Python](https://stamina.hynek.me/en/stable/tutorial.html#retries).
2023-12-21 15:09:45 +03:00
- [retry](https://github.com/Soostone/retry) as case study for what needs to be supported.
2023-12-30 14:38:00 +03:00
<details>
<summary>Test setup</summary>
```haskell
main = undefined
```
</details>