1use crate::future::poll_fn;
2use crate::time::{sleep_until, Duration, Instant, Sleep};
3use crate::util::trace;
4
5use std::future::Future;
6use std::panic::Location;
7use std::pin::Pin;
8use std::task::{Context, Poll};
9
10/// Creates new [`Interval`] that yields with interval of `period`. The first
11/// tick completes immediately. The default [`MissedTickBehavior`] is
12/// [`Burst`](MissedTickBehavior::Burst), but this can be configured
13/// by calling [`set_missed_tick_behavior`](Interval::set_missed_tick_behavior).
14///
15/// An interval will tick indefinitely. At any time, the [`Interval`] value can
16/// be dropped. This cancels the interval.
17///
18/// This function is equivalent to
19/// [`interval_at(Instant::now(), period)`](interval_at).
20///
21/// # Panics
22///
23/// This function panics if `period` is zero.
24///
25/// # Examples
26///
27/// ```
28/// use tokio::time::{self, Duration};
29///
30/// #[tokio::main]
31/// async fn main() {
32/// let mut interval = time::interval(Duration::from_millis(10));
33///
34/// interval.tick().await; // ticks immediately
35/// interval.tick().await; // ticks after 10ms
36/// interval.tick().await; // ticks after 10ms
37///
38/// // approximately 20ms have elapsed.
39/// }
40/// ```
41///
42/// A simple example using `interval` to execute a task every two seconds.
43///
44/// The difference between `interval` and [`sleep`] is that an [`Interval`]
45/// measures the time since the last tick, which means that [`.tick().await`]
46/// may wait for a shorter time than the duration specified for the interval
47/// if some time has passed between calls to [`.tick().await`].
48///
49/// If the tick in the example below was replaced with [`sleep`], the task
50/// would only be executed once every three seconds, and not every two
51/// seconds.
52///
53/// ```
54/// use tokio::time;
55///
56/// async fn task_that_takes_a_second() {
57/// println!("hello");
58/// time::sleep(time::Duration::from_secs(1)).await
59/// }
60///
61/// #[tokio::main]
62/// async fn main() {
63/// let mut interval = time::interval(time::Duration::from_secs(2));
64/// for _i in 0..5 {
65/// interval.tick().await;
66/// task_that_takes_a_second().await;
67/// }
68/// }
69/// ```
70///
71/// [`sleep`]: crate::time::sleep()
72/// [`.tick().await`]: Interval::tick
73#[track_caller]
74pub fn interval(period: Duration) -> Interval {
75 assert!(period > Duration::new(0, 0), "`period` must be non-zero.");
76 internal_interval_at(start:Instant::now(), period, location:trace::caller_location())
77}
78
79/// Creates new [`Interval`] that yields with interval of `period` with the
80/// first tick completing at `start`. The default [`MissedTickBehavior`] is
81/// [`Burst`](MissedTickBehavior::Burst), but this can be configured
82/// by calling [`set_missed_tick_behavior`](Interval::set_missed_tick_behavior).
83///
84/// An interval will tick indefinitely. At any time, the [`Interval`] value can
85/// be dropped. This cancels the interval.
86///
87/// # Panics
88///
89/// This function panics if `period` is zero.
90///
91/// # Examples
92///
93/// ```
94/// use tokio::time::{interval_at, Duration, Instant};
95///
96/// #[tokio::main]
97/// async fn main() {
98/// let start = Instant::now() + Duration::from_millis(50);
99/// let mut interval = interval_at(start, Duration::from_millis(10));
100///
101/// interval.tick().await; // ticks after 50ms
102/// interval.tick().await; // ticks after 10ms
103/// interval.tick().await; // ticks after 10ms
104///
105/// // approximately 70ms have elapsed.
106/// }
107/// ```
108#[track_caller]
109pub fn interval_at(start: Instant, period: Duration) -> Interval {
110 assert!(period > Duration::new(0, 0), "`period` must be non-zero.");
111 internal_interval_at(start, period, location:trace::caller_location())
112}
113
114#[cfg_attr(not(all(tokio_unstable, feature = "tracing")), allow(unused_variables))]
115fn internal_interval_at(
116 start: Instant,
117 period: Duration,
118 location: Option<&'static Location<'static>>,
119) -> Interval {
120 #[cfg(all(tokio_unstable, feature = "tracing"))]
121 let resource_span = {
122 let location = location.expect("should have location if tracing");
123
124 tracing::trace_span!(
125 parent: None,
126 "runtime.resource",
127 concrete_type = "Interval",
128 kind = "timer",
129 loc.file = location.file(),
130 loc.line = location.line(),
131 loc.col = location.column(),
132 )
133 };
134
135 #[cfg(all(tokio_unstable, feature = "tracing"))]
136 let delay = resource_span.in_scope(|| Box::pin(sleep_until(start)));
137
138 #[cfg(not(all(tokio_unstable, feature = "tracing")))]
139 let delay = Box::pin(sleep_until(start));
140
141 Interval {
142 delay,
143 period,
144 missed_tick_behavior: MissedTickBehavior::default(),
145 #[cfg(all(tokio_unstable, feature = "tracing"))]
146 resource_span,
147 }
148}
149
150/// Defines the behavior of an [`Interval`] when it misses a tick.
151///
152/// Sometimes, an [`Interval`]'s tick is missed. For example, consider the
153/// following:
154///
155/// ```
156/// use tokio::time::{self, Duration};
157/// # async fn task_that_takes_one_to_three_millis() {}
158///
159/// #[tokio::main]
160/// async fn main() {
161/// // ticks every 2 milliseconds
162/// let mut interval = time::interval(Duration::from_millis(2));
163/// for _ in 0..5 {
164/// interval.tick().await;
165/// // if this takes more than 2 milliseconds, a tick will be delayed
166/// task_that_takes_one_to_three_millis().await;
167/// }
168/// }
169/// ```
170///
171/// Generally, a tick is missed if too much time is spent without calling
172/// [`Interval::tick()`].
173///
174/// By default, when a tick is missed, [`Interval`] fires ticks as quickly as it
175/// can until it is "caught up" in time to where it should be.
176/// `MissedTickBehavior` can be used to specify a different behavior for
177/// [`Interval`] to exhibit. Each variant represents a different strategy.
178///
179/// Note that because the executor cannot guarantee exact precision with timers,
180/// these strategies will only apply when the delay is greater than 5
181/// milliseconds.
182#[derive(Debug, Clone, Copy, PartialEq, Eq)]
183pub enum MissedTickBehavior {
184 /// Ticks as fast as possible until caught up.
185 ///
186 /// When this strategy is used, [`Interval`] schedules ticks "normally" (the
187 /// same as it would have if the ticks hadn't been delayed), which results
188 /// in it firing ticks as fast as possible until it is caught up in time to
189 /// where it should be. Unlike [`Delay`] and [`Skip`], the ticks yielded
190 /// when `Burst` is used (the [`Instant`]s that [`tick`](Interval::tick)
191 /// yields) aren't different than they would have been if a tick had not
192 /// been missed. Like [`Skip`], and unlike [`Delay`], the ticks may be
193 /// shortened.
194 ///
195 /// This looks something like this:
196 /// ```text
197 /// Expected ticks: | 1 | 2 | 3 | 4 | 5 | 6 |
198 /// Actual ticks: | work -----| delay | work | work | work -| work -----|
199 /// ```
200 ///
201 /// In code:
202 ///
203 /// ```
204 /// use tokio::time::{interval, Duration};
205 /// # async fn task_that_takes_200_millis() {}
206 ///
207 /// # #[tokio::main(flavor = "current_thread")]
208 /// # async fn main() {
209 /// let mut interval = interval(Duration::from_millis(50));
210 ///
211 /// // First tick resolves immediately after creation
212 /// interval.tick().await;
213 ///
214 /// task_that_takes_200_millis().await;
215 /// // The `Interval` has missed a tick
216 ///
217 /// // Since we have exceeded our timeout, this will resolve immediately
218 /// interval.tick().await;
219 ///
220 /// // Since we are more than 100ms after the start of `interval`, this will
221 /// // also resolve immediately.
222 /// interval.tick().await;
223 ///
224 /// // Also resolves immediately, because it was supposed to resolve at
225 /// // 150ms after the start of `interval`
226 /// interval.tick().await;
227 ///
228 /// // Resolves immediately
229 /// interval.tick().await;
230 ///
231 /// // Since we have gotten to 200ms after the start of `interval`, this
232 /// // will resolve after 50ms
233 /// interval.tick().await;
234 /// # }
235 /// ```
236 ///
237 /// This is the default behavior when [`Interval`] is created with
238 /// [`interval`] and [`interval_at`].
239 ///
240 /// [`Delay`]: MissedTickBehavior::Delay
241 /// [`Skip`]: MissedTickBehavior::Skip
242 Burst,
243
244 /// Tick at multiples of `period` from when [`tick`] was called, rather than
245 /// from `start`.
246 ///
247 /// When this strategy is used and [`Interval`] has missed a tick, instead
248 /// of scheduling ticks to fire at multiples of `period` from `start` (the
249 /// time when the first tick was fired), it schedules all future ticks to
250 /// happen at a regular `period` from the point when [`tick`] was called.
251 /// Unlike [`Burst`] and [`Skip`], ticks are not shortened, and they aren't
252 /// guaranteed to happen at a multiple of `period` from `start` any longer.
253 ///
254 /// This looks something like this:
255 /// ```text
256 /// Expected ticks: | 1 | 2 | 3 | 4 | 5 | 6 |
257 /// Actual ticks: | work -----| delay | work -----| work -----| work -----|
258 /// ```
259 ///
260 /// In code:
261 ///
262 /// ```
263 /// use tokio::time::{interval, Duration, MissedTickBehavior};
264 /// # async fn task_that_takes_more_than_50_millis() {}
265 ///
266 /// # #[tokio::main(flavor = "current_thread")]
267 /// # async fn main() {
268 /// let mut interval = interval(Duration::from_millis(50));
269 /// interval.set_missed_tick_behavior(MissedTickBehavior::Delay);
270 ///
271 /// task_that_takes_more_than_50_millis().await;
272 /// // The `Interval` has missed a tick
273 ///
274 /// // Since we have exceeded our timeout, this will resolve immediately
275 /// interval.tick().await;
276 ///
277 /// // But this one, rather than also resolving immediately, as might happen
278 /// // with the `Burst` or `Skip` behaviors, will not resolve until
279 /// // 50ms after the call to `tick` up above. That is, in `tick`, when we
280 /// // recognize that we missed a tick, we schedule the next tick to happen
281 /// // 50ms (or whatever the `period` is) from right then, not from when
282 /// // were *supposed* to tick
283 /// interval.tick().await;
284 /// # }
285 /// ```
286 ///
287 /// [`Burst`]: MissedTickBehavior::Burst
288 /// [`Skip`]: MissedTickBehavior::Skip
289 /// [`tick`]: Interval::tick
290 Delay,
291
292 /// Skips missed ticks and tick on the next multiple of `period` from
293 /// `start`.
294 ///
295 /// When this strategy is used, [`Interval`] schedules the next tick to fire
296 /// at the next-closest tick that is a multiple of `period` away from
297 /// `start` (the point where [`Interval`] first ticked). Like [`Burst`], all
298 /// ticks remain multiples of `period` away from `start`, but unlike
299 /// [`Burst`], the ticks may not be *one* multiple of `period` away from the
300 /// last tick. Like [`Delay`], the ticks are no longer the same as they
301 /// would have been if ticks had not been missed, but unlike [`Delay`], and
302 /// like [`Burst`], the ticks may be shortened to be less than one `period`
303 /// away from each other.
304 ///
305 /// This looks something like this:
306 /// ```text
307 /// Expected ticks: | 1 | 2 | 3 | 4 | 5 | 6 |
308 /// Actual ticks: | work -----| delay | work ---| work -----| work -----|
309 /// ```
310 ///
311 /// In code:
312 ///
313 /// ```
314 /// use tokio::time::{interval, Duration, MissedTickBehavior};
315 /// # async fn task_that_takes_75_millis() {}
316 ///
317 /// # #[tokio::main(flavor = "current_thread")]
318 /// # async fn main() {
319 /// let mut interval = interval(Duration::from_millis(50));
320 /// interval.set_missed_tick_behavior(MissedTickBehavior::Skip);
321 ///
322 /// task_that_takes_75_millis().await;
323 /// // The `Interval` has missed a tick
324 ///
325 /// // Since we have exceeded our timeout, this will resolve immediately
326 /// interval.tick().await;
327 ///
328 /// // This one will resolve after 25ms, 100ms after the start of
329 /// // `interval`, which is the closest multiple of `period` from the start
330 /// // of `interval` after the call to `tick` up above.
331 /// interval.tick().await;
332 /// # }
333 /// ```
334 ///
335 /// [`Burst`]: MissedTickBehavior::Burst
336 /// [`Delay`]: MissedTickBehavior::Delay
337 Skip,
338}
339
340impl MissedTickBehavior {
341 /// If a tick is missed, this method is called to determine when the next tick should happen.
342 fn next_timeout(&self, timeout: Instant, now: Instant, period: Duration) -> Instant {
343 match self {
344 Self::Burst => timeout + period,
345 Self::Delay => now + period,
346 Self::Skip => {
347 now + period
348 - Duration::from_nanos(
349 ((now - timeout).as_nanos() % period.as_nanos())
350 .try_into()
351 // This operation is practically guaranteed not to
352 // fail, as in order for it to fail, `period` would
353 // have to be longer than `now - timeout`, and both
354 // would have to be longer than 584 years.
355 //
356 // If it did fail, there's not a good way to pass
357 // the error along to the user, so we just panic.
358 .expect(
359 "too much time has elapsed since the interval was supposed to tick",
360 ),
361 )
362 }
363 }
364 }
365}
366
367impl Default for MissedTickBehavior {
368 /// Returns [`MissedTickBehavior::Burst`].
369 ///
370 /// For most usecases, the [`Burst`] strategy is what is desired.
371 /// Additionally, to preserve backwards compatibility, the [`Burst`]
372 /// strategy must be the default. For these reasons,
373 /// [`MissedTickBehavior::Burst`] is the default for [`MissedTickBehavior`].
374 /// See [`Burst`] for more details.
375 ///
376 /// [`Burst`]: MissedTickBehavior::Burst
377 fn default() -> Self {
378 Self::Burst
379 }
380}
381
382/// Interval returned by [`interval`] and [`interval_at`].
383///
384/// This type allows you to wait on a sequence of instants with a certain
385/// duration between each instant. Unlike calling [`sleep`] in a loop, this lets
386/// you count the time spent between the calls to [`sleep`] as well.
387///
388/// An `Interval` can be turned into a `Stream` with [`IntervalStream`].
389///
390/// [`IntervalStream`]: https://docs.rs/tokio-stream/latest/tokio_stream/wrappers/struct.IntervalStream.html
391/// [`sleep`]: crate::time::sleep()
392#[derive(Debug)]
393pub struct Interval {
394 /// Future that completes the next time the `Interval` yields a value.
395 delay: Pin<Box<Sleep>>,
396
397 /// The duration between values yielded by `Interval`.
398 period: Duration,
399
400 /// The strategy `Interval` should use when a tick is missed.
401 missed_tick_behavior: MissedTickBehavior,
402
403 #[cfg(all(tokio_unstable, feature = "tracing"))]
404 resource_span: tracing::Span,
405}
406
407impl Interval {
408 /// Completes when the next instant in the interval has been reached.
409 ///
410 /// # Cancel safety
411 ///
412 /// This method is cancellation safe. If `tick` is used as the branch in a `tokio::select!` and
413 /// another branch completes first, then no tick has been consumed.
414 ///
415 /// # Examples
416 ///
417 /// ```
418 /// use tokio::time;
419 ///
420 /// use std::time::Duration;
421 ///
422 /// #[tokio::main]
423 /// async fn main() {
424 /// let mut interval = time::interval(Duration::from_millis(10));
425 ///
426 /// interval.tick().await;
427 /// // approximately 0ms have elapsed. The first tick completes immediately.
428 /// interval.tick().await;
429 /// interval.tick().await;
430 ///
431 /// // approximately 20ms have elapsed.
432 /// }
433 /// ```
434 pub async fn tick(&mut self) -> Instant {
435 #[cfg(all(tokio_unstable, feature = "tracing"))]
436 let resource_span = self.resource_span.clone();
437 #[cfg(all(tokio_unstable, feature = "tracing"))]
438 let instant = trace::async_op(
439 || poll_fn(|cx| self.poll_tick(cx)),
440 resource_span,
441 "Interval::tick",
442 "poll_tick",
443 false,
444 );
445 #[cfg(not(all(tokio_unstable, feature = "tracing")))]
446 let instant = poll_fn(|cx| self.poll_tick(cx));
447
448 instant.await
449 }
450
451 /// Polls for the next instant in the interval to be reached.
452 ///
453 /// This method can return the following values:
454 ///
455 /// * `Poll::Pending` if the next instant has not yet been reached.
456 /// * `Poll::Ready(instant)` if the next instant has been reached.
457 ///
458 /// When this method returns `Poll::Pending`, the current task is scheduled
459 /// to receive a wakeup when the instant has elapsed. Note that on multiple
460 /// calls to `poll_tick`, only the [`Waker`](std::task::Waker) from the
461 /// [`Context`] passed to the most recent call is scheduled to receive a
462 /// wakeup.
463 pub fn poll_tick(&mut self, cx: &mut Context<'_>) -> Poll<Instant> {
464 // Wait for the delay to be done
465 ready!(Pin::new(&mut self.delay).poll(cx));
466
467 // Get the time when we were scheduled to tick
468 let timeout = self.delay.deadline();
469
470 let now = Instant::now();
471
472 // If a tick was not missed, and thus we are being called before the
473 // next tick is due, just schedule the next tick normally, one `period`
474 // after `timeout`
475 //
476 // However, if a tick took excessively long and we are now behind,
477 // schedule the next tick according to how the user specified with
478 // `MissedTickBehavior`
479 let next = if now > timeout + Duration::from_millis(5) {
480 self.missed_tick_behavior
481 .next_timeout(timeout, now, self.period)
482 } else {
483 timeout + self.period
484 };
485
486 // When we arrive here, the internal delay returned `Poll::Ready`.
487 // Reset the delay but do not register it. It should be registered with
488 // the next call to [`poll_tick`].
489 self.delay.as_mut().reset_without_reregister(next);
490
491 // Return the time when we were scheduled to tick
492 Poll::Ready(timeout)
493 }
494
495 /// Resets the interval to complete one period after the current time.
496 ///
497 /// This method ignores [`MissedTickBehavior`] strategy.
498 ///
499 /// This is equivalent to calling `reset_at(Instant::now() + period)`.
500 ///
501 /// # Examples
502 ///
503 /// ```
504 /// use tokio::time;
505 ///
506 /// use std::time::Duration;
507 ///
508 /// #[tokio::main]
509 /// async fn main() {
510 /// let mut interval = time::interval(Duration::from_millis(100));
511 ///
512 /// interval.tick().await;
513 ///
514 /// time::sleep(Duration::from_millis(50)).await;
515 /// interval.reset();
516 ///
517 /// interval.tick().await;
518 /// interval.tick().await;
519 ///
520 /// // approximately 250ms have elapsed.
521 /// }
522 /// ```
523 pub fn reset(&mut self) {
524 self.delay.as_mut().reset(Instant::now() + self.period);
525 }
526
527 /// Resets the interval immediately.
528 ///
529 /// This method ignores [`MissedTickBehavior`] strategy.
530 ///
531 /// This is equivalent to calling `reset_at(Instant::now())`.
532 ///
533 /// # Examples
534 ///
535 /// ```
536 /// use tokio::time;
537 ///
538 /// use std::time::Duration;
539 ///
540 /// #[tokio::main]
541 /// async fn main() {
542 /// let mut interval = time::interval(Duration::from_millis(100));
543 ///
544 /// interval.tick().await;
545 ///
546 /// time::sleep(Duration::from_millis(50)).await;
547 /// interval.reset_immediately();
548 ///
549 /// interval.tick().await;
550 /// interval.tick().await;
551 ///
552 /// // approximately 150ms have elapsed.
553 /// }
554 /// ```
555 pub fn reset_immediately(&mut self) {
556 self.delay.as_mut().reset(Instant::now());
557 }
558
559 /// Resets the interval after the specified [`std::time::Duration`].
560 ///
561 /// This method ignores [`MissedTickBehavior`] strategy.
562 ///
563 /// This is equivalent to calling `reset_at(Instant::now() + after)`.
564 ///
565 /// # Examples
566 ///
567 /// ```
568 /// use tokio::time;
569 ///
570 /// use std::time::Duration;
571 ///
572 /// #[tokio::main]
573 /// async fn main() {
574 /// let mut interval = time::interval(Duration::from_millis(100));
575 /// interval.tick().await;
576 ///
577 /// time::sleep(Duration::from_millis(50)).await;
578 ///
579 /// let after = Duration::from_millis(20);
580 /// interval.reset_after(after);
581 ///
582 /// interval.tick().await;
583 /// interval.tick().await;
584 ///
585 /// // approximately 170ms have elapsed.
586 /// }
587 /// ```
588 pub fn reset_after(&mut self, after: Duration) {
589 self.delay.as_mut().reset(Instant::now() + after);
590 }
591
592 /// Resets the interval to a [`crate::time::Instant`] deadline.
593 ///
594 /// Sets the next tick to expire at the given instant. If the instant is in
595 /// the past, then the [`MissedTickBehavior`] strategy will be used to
596 /// catch up. If the instant is in the future, then the next tick will
597 /// complete at the given instant, even if that means that it will sleep for
598 /// longer than the duration of this [`Interval`]. If the [`Interval`] had
599 /// any missed ticks before calling this method, then those are discarded.
600 ///
601 /// # Examples
602 ///
603 /// ```
604 /// use tokio::time::{self, Instant};
605 ///
606 /// use std::time::Duration;
607 ///
608 /// #[tokio::main]
609 /// async fn main() {
610 /// let mut interval = time::interval(Duration::from_millis(100));
611 /// interval.tick().await;
612 ///
613 /// time::sleep(Duration::from_millis(50)).await;
614 ///
615 /// let deadline = Instant::now() + Duration::from_millis(30);
616 /// interval.reset_at(deadline);
617 ///
618 /// interval.tick().await;
619 /// interval.tick().await;
620 ///
621 /// // approximately 180ms have elapsed.
622 /// }
623 /// ```
624 pub fn reset_at(&mut self, deadline: Instant) {
625 self.delay.as_mut().reset(deadline);
626 }
627
628 /// Returns the [`MissedTickBehavior`] strategy currently being used.
629 pub fn missed_tick_behavior(&self) -> MissedTickBehavior {
630 self.missed_tick_behavior
631 }
632
633 /// Sets the [`MissedTickBehavior`] strategy that should be used.
634 pub fn set_missed_tick_behavior(&mut self, behavior: MissedTickBehavior) {
635 self.missed_tick_behavior = behavior;
636 }
637
638 /// Returns the period of the interval.
639 pub fn period(&self) -> Duration {
640 self.period
641 }
642}
643