1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
//! Controls whether Taskvisor starts another attempt and when it starts.
//!
//! Applications normally select policies through [`TaskSpec`](crate::TaskSpec) or supervisor-wide
//! [`TaskDefaults`](crate::TaskDefaults). Admission resolves those choices once.
//! Taskvisor then applies them after every attempt.
//!
//! ```text
//! TaskSpec + TaskDefaults
//! │ resolved policy
//! ▼
//! task actor
//! ├── success ──► RestartPolicy ──► stop or repeat
//! ├── retryable failure ──► RestartPolicy + retry limit
//! │ │ retry allowed
//! │ ▼
//! │ BackoffPolicy
//! │ │ base delay
//! │ ▼
//! │ JitterPolicy ──► retry delay
//! └── fatal or canceled ──► stop
//! ```
//!
//! [`RestartPolicy`] decides whether another attempt is eligible.
//! [`BackoffPolicy`] computes the delay after a retryable failure.
//! [`JitterPolicy`] can spread that delay to avoid synchronized retries.
//!
//! # Choosing a task lifecycle
//!
//! - Use [`TaskSpec::periodic`](crate::TaskSpec::periodic) to repeat after success and allow retries for retryable failures.
//! - Use [`TaskSpec::from_defaults`](crate::TaskSpec::from_defaults) to inherit every runtime default.
//! - Use [`TaskSpec::restartable`](crate::TaskSpec::restartable) to retry retryable failures.
//! - Use [`TaskSpec::once`](crate::TaskSpec::once) for one attempt only.
//!
//! Use [`TaskSpec::with_restart`](crate::TaskSpec::with_restart) for a custom combination.
//! Backoff and the retry limit only affect retryable failures.
//! A periodic success uses its configured interval instead.
//!
//! The built-in defaults use [`RestartPolicy::OnFailure`], exponential backoff from `200ms` to `30s`,
//! equal jitter, no attempt timeout, and no retry-count limit. Named backoff constructors have no
//! jitter unless it is added explicitly.
//!
//! The retry limit counts retries after the first failed attempt in one failure streak.
//! Success resets the count. Fatal errors and cancellation always stop.
//!
//! # Example
//!
//! ```rust
//! use std::num::NonZeroU32;
//! use std::time::Duration;
//! use taskvisor::{BackoffPolicy, JitterPolicy, TaskError, TaskFn, TaskSpec};
//!
//! let task = TaskFn::arc(|_ctx| async {
//! Err(TaskError::fail("temporary upstream failure"))
//! });
//! let spec = TaskSpec::restartable("api-sync", task)
//! .with_backoff(
//! BackoffPolicy::exponential(Duration::from_millis(250))
//! .with_max(Duration::from_secs(20))
//! .with_jitter(JitterPolicy::Equal),
//! )
//! .with_max_retries(NonZeroU32::new(5).unwrap());
//! ```
pub use ;
pub use RestartPolicy;
pub use JitterPolicy;