8
8
9
9
use futures_util:: { future:: BoxFuture , stream:: Stream } ;
10
10
use std:: { fmt:: Debug , future:: Future , time:: Duration } ;
11
+ use futures_util:: stream:: unfold;
11
12
use thiserror:: Error ;
12
13
13
14
/// A runtime is an abstraction of an async runtime like [Tokio] or [async-std]. It allows
14
- /// OpenTelemetry to work with any current and hopefully future runtime implementation .
15
+ /// OpenTelemetry to work with any current and hopefully future runtime implementations .
15
16
///
16
17
/// [Tokio]: https://crates.io/crates/tokio
17
18
/// [async-std]: https://crates.io/crates/async-std
19
+ ///
20
+ /// # Note
21
+ ///
22
+ /// OpenTelemetry expects a *multi-threaded* runtime because its types can move across threads.
23
+ /// For this reason, this trait requires the `Send` and `Sync` bounds. Single-threaded runtimes
24
+ /// can implement this trait in a way that spawns the tasks on the same thread as the calling code.
18
25
#[ cfg( feature = "experimental_async_runtime" ) ]
19
26
pub trait Runtime : Clone + Send + Sync + ' static {
20
- /// A future stream, which returns items in a previously specified interval. The item type is
21
- /// not important.
22
- type Interval : Stream + Send ;
23
-
24
- /// A future, which resolves after a previously specified amount of time. The output type is
25
- /// not important.
26
- type Delay : Future + Send + Unpin ;
27
-
28
- /// Create a [futures_util::stream::Stream], which returns a new item every
29
- /// [std::time::Duration].
30
- fn interval ( & self , duration : Duration ) -> Self :: Interval ;
31
-
32
27
/// Spawn a new task or thread, which executes the given future.
33
28
///
34
29
/// # Note
35
30
///
36
31
/// This is mainly used to run batch span processing in the background. Note, that the function
37
32
/// does not return a handle. OpenTelemetry will use a different way to wait for the future to
38
- /// finish when TracerProvider gets shutdown. At the moment this happens by blocking the
33
+ /// finish when ` TracerProvider` gets shutdown. At the moment this happens by blocking the
39
34
/// current thread. This means runtime implementations need to make sure they can still execute
40
35
/// the given future even if the main thread is blocked.
41
36
fn spawn ( & self , future : BoxFuture < ' static , ( ) > ) ;
42
37
43
38
/// Return a new future, which resolves after the specified [std::time::Duration].
44
- fn delay ( & self , duration : Duration ) -> Self :: Delay ;
39
+ fn delay ( & self , duration : Duration ) -> impl Future < Output = ( ) > + Send + Sync + ' static ;
40
+ }
41
+
42
+ /// Uses the given runtime to produce an interval stream.
43
+ #[ cfg( feature = "experimental_async_runtime" ) ]
44
+ pub ( crate ) fn to_interval_stream < T : Runtime > ( runtime : T , interval : Duration ) -> impl Stream < Item = ( ) > {
45
+ unfold ( ( ) , move |_| {
46
+ let runtime_cloned = runtime. clone ( ) ;
47
+
48
+ async move {
49
+ runtime_cloned. delay ( interval) . await ;
50
+ Some ( ( ( ) , ( ) ) )
51
+ }
52
+ } )
45
53
}
46
54
47
55
/// Runtime implementation, which works with Tokio's multi thread runtime.
@@ -59,21 +67,14 @@ pub struct Tokio;
59
67
doc( cfg( all( feature = "experimental_async_runtime" , feature = "rt-tokio" ) ) )
60
68
) ]
61
69
impl Runtime for Tokio {
62
- type Interval = tokio_stream:: wrappers:: IntervalStream ;
63
- type Delay = :: std:: pin:: Pin < Box < tokio:: time:: Sleep > > ;
64
-
65
- fn interval ( & self , duration : Duration ) -> Self :: Interval {
66
- crate :: util:: tokio_interval_stream ( duration)
67
- }
68
-
69
70
fn spawn ( & self , future : BoxFuture < ' static , ( ) > ) {
70
71
#[ allow( clippy:: let_underscore_future) ]
71
72
// we don't have to await on the returned future to execute
72
73
let _ = tokio:: spawn ( future) ;
73
74
}
74
75
75
- fn delay ( & self , duration : Duration ) -> Self :: Delay {
76
- Box :: pin ( tokio:: time:: sleep ( duration) )
76
+ fn delay ( & self , duration : Duration ) -> impl Future < Output = ( ) > + Send + Sync + ' static {
77
+ tokio:: time:: sleep ( duration)
77
78
}
78
79
}
79
80
@@ -104,13 +105,6 @@ pub struct TokioCurrentThread;
104
105
) ) )
105
106
) ]
106
107
impl Runtime for TokioCurrentThread {
107
- type Interval = tokio_stream:: wrappers:: IntervalStream ;
108
- type Delay = :: std:: pin:: Pin < Box < tokio:: time:: Sleep > > ;
109
-
110
- fn interval ( & self , duration : Duration ) -> Self :: Interval {
111
- crate :: util:: tokio_interval_stream ( duration)
112
- }
113
-
114
108
fn spawn ( & self , future : BoxFuture < ' static , ( ) > ) {
115
109
// We cannot force push tracing in current thread tokio scheduler because we rely on
116
110
// BatchSpanProcessor to export spans in a background task, meanwhile we need to block the
@@ -127,8 +121,8 @@ impl Runtime for TokioCurrentThread {
127
121
} ) ;
128
122
}
129
123
130
- fn delay ( & self , duration : Duration ) -> Self :: Delay {
131
- Box :: pin ( tokio:: time:: sleep ( duration) )
124
+ fn delay ( & self , duration : Duration ) -> impl Future < Output = ( ) > + Send + Sync + ' static {
125
+ tokio:: time:: sleep ( duration)
132
126
}
133
127
}
134
128
@@ -147,20 +141,13 @@ pub struct AsyncStd;
147
141
doc( cfg( all( feature = "experimental_async_runtime" , feature = "rt-async-std" ) ) )
148
142
) ]
149
143
impl Runtime for AsyncStd {
150
- type Interval = async_std:: stream:: Interval ;
151
- type Delay = BoxFuture < ' static , ( ) > ;
152
-
153
- fn interval ( & self , duration : Duration ) -> Self :: Interval {
154
- async_std:: stream:: interval ( duration)
155
- }
156
-
157
144
fn spawn ( & self , future : BoxFuture < ' static , ( ) > ) {
158
145
#[ allow( clippy:: let_underscore_future) ]
159
146
let _ = async_std:: task:: spawn ( future) ;
160
147
}
161
148
162
- fn delay ( & self , duration : Duration ) -> Self :: Delay {
163
- Box :: pin ( async_std:: task:: sleep ( duration) )
149
+ fn delay ( & self , duration : Duration ) -> impl Future < Output = ( ) > + Send + Sync + ' static {
150
+ async_std:: task:: sleep ( duration)
164
151
}
165
152
}
166
153
@@ -193,7 +180,7 @@ pub enum TrySendError {
193
180
/// Send failed due to the channel being closed.
194
181
#[ error( "cannot send message to batch processor as the channel is closed" ) ]
195
182
ChannelClosed ,
196
- /// Any other send error that isnt covered above.
183
+ /// Any other send error that isn't covered above.
197
184
#[ error( transparent) ]
198
185
Other ( #[ from] Box < dyn std:: error:: Error + Send + Sync + ' static > ) ,
199
186
}
0 commit comments