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
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
//! [`MainRuntime`]: the app's runtime as a handler reaches it, and the explicit way to send work
//! there from a dedicated thread.
use Future;
use Handle;
use ;
/// The runtime the app runs on, as a handler reaches it: `Ctx(main): Ctx<MainRuntime>` as a
/// parameter, or [`Context::main_runtime`](super::Context::main_runtime).
///
/// A handler on dedicated threads (`threads(n)`) runs on its own thread, and so does everything
/// it leaves behind: a plain `tokio::spawn`, a timer, an `and_after` continuation, an `after(..)`
/// hook and the timer of a `retry_after` copy. `MainRuntime` is the one explicit way to send work
/// to the app's runtime instead: [`spawn`](Self::spawn) starts it there and moves on,
/// [`run`](Self::run) runs it there and hands its output back. What is sent must be `Send`.
/// A plain `tokio::spawn` on a dedicated thread lives as long as that thread: a task still
/// pending when the subscription ends is dropped with the thread's runtime.
/// On any other placement the handler already runs on this runtime.
///
/// # Examples
///
/// ```
/// # #[cfg(all(feature = "macros", feature = "json"))]
/// # mod demo {
/// use ruststream::prelude::*;
///
/// #[derive(serde::Deserialize)]
/// struct Job {
/// id: u64,
/// }
///
/// async fn notify(_id: u64) {}
///
/// async fn lookup(id: u64) -> u64 {
/// id * 2
/// }
///
/// #[subscriber("jobs", threads(4))]
/// async fn index(job: &Job, Ctx(main): Ctx<MainRuntime>) -> HandlerOutcome {
/// // The notification leaves the thread; the handler does not wait for it.
/// main.spawn(notify(job.id));
/// // The lookup runs on the app's runtime, and its answer comes back here.
/// match main.run(lookup(job.id)).await {
/// Ok(_answer) => HandlerOutcome::ack(),
/// Err(_) => HandlerOutcome::retry(),
/// }
/// }
/// # }
/// ```
;