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
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
//! Closure-based [`Task`] implementation.
use ;
use CancellationToken;
use crate::;
/// Closure-based [`Task`] implementation.
///
/// - Wraps `F: Fn(CancellationToken) -> Future`
/// - Each [`spawn`](Task::spawn) invokes the closure to produce a fresh, independent future.
///
/// ## Stateless task
///
/// ```rust
/// use tokio_util::sync::CancellationToken;
/// use taskvisor::{TaskFn, TaskRef, TaskError};
///
/// let worker: TaskRef = TaskFn::arc("worker", |_ctx: CancellationToken| async move {
/// // do some work and complete
/// Ok(())
/// });
/// ```
///
/// ## Stateful task (shared state via `Arc`)
///
/// ```rust
/// use std::sync::{Arc, atomic::{AtomicU64, Ordering}};
/// use std::time::Duration;
/// use tokio_util::sync::CancellationToken;
///
/// use taskvisor::{TaskFn, TaskRef, TaskError};
///
/// let counter = Arc::new(AtomicU64::new(0));
/// let task: TaskRef = TaskFn::arc("counter", {
/// let counter = counter.clone();
/// move |ctx: CancellationToken| {
/// // clone per-attempt; the underlying value persists across restarts.
/// let counter = counter.clone();
/// async move {
/// loop {
/// tokio::select! {
/// _ = ctx.cancelled() => return Err(TaskError::Canceled),
/// _ = tokio::time::sleep(Duration::from_secs(1)) => {
/// let _ = counter.fetch_add(1, Ordering::Relaxed);
/// }
/// }
/// }
/// }
/// }
/// });
/// ```
///
/// ## Also
///
/// - See the [`Task`](crate::Task) trait documentation.
/// - To configure restart, backoff, and timeout see [`TaskSpec`](crate::TaskSpec).