Struct clokwerk::AsyncScheduler[][src]

pub struct AsyncScheduler<Tz = Local, Tp = ChronoTimeProvider> where
    Tz: TimeZone,
    Tp: TimeProvider
{ /* fields omitted */ }

An asynchronous job scheduler, for use with Futures.

The asynchronous scheduler works almost identically to the synchronous one, except that instead of taking functions or closures returning (), it takes functions or closures returning values implementing Future<Output = ()>.

Unlike the synchronous version, there is no watch_thread method, as it would tie this crate to a specific runtime, and also because it’s trivial to implement by hand. For example, using tokio:

tokio::spawn(async move {
  loop {
    scheduler.run_pending().await;
    tokio::time::sleep(Duration::from_millis(100)).await;
  }
});

For async_std:

async_std::task::spawn(async move {
  loop {
    scheduler.run_pending().await;
    async_std::task::sleep(Duration::from_millis(100)).await;
  }
});

Usage examples

The examples below are intended to demonstrate how to work with various types of Future. See synchronous examples for more examples of how to schedule tasks.

// Scheduler, trait for .seconds(), .minutes(), etc., and trait with job scheduling methods
use clokwerk::{AsyncScheduler, TimeUnits, Job};
// Import week days and WeekDay
use clokwerk::Interval::*;
use std::time::Duration;

// Create a new scheduler
let mut scheduler = AsyncScheduler::new();
// Add some tasks to it
scheduler
    .every(10.minutes())
        .plus(30.seconds())
    .run(|| async { println!("Simplest is just using an async block"); });
scheduler
    .every(1.day())
        .at("3:20 pm")
    .run(|| some_async_fn());
scheduler
    .every(Wednesday)
        .at("14:20:17")
    .run(some_async_fn);
scheduler
    .every(Tuesday)
        .at("14:20:17")
    .and_every(Thursday)
        .at("15:00")
    .run(|| std::pin::Pin::from(returns_boxed_future()));
scheduler
    .every(Weekday)
    .run(|| returns_pinned_boxed_future());
scheduler
    .every(1.day())
        .at("3:20 pm")
    .run(returns_pinned_boxed_future).once();
// Manually run the scheduler forever
loop {
    scheduler.run_pending().await;
    tokio::time::sleep(Duration::from_millis(10)).await;
}

// Or spawn a task to run it forever
tokio::spawn(async move {
  loop {
    scheduler.run_pending().await;
    tokio::time::sleep(Duration::from_millis(100)).await;
  }
});

Implementations

impl AsyncScheduler[src]

pub fn new() -> Self[src]

Create a new scheduler. Dates and times will be interpretted using the local timezone

pub fn with_tz<Tz: TimeZone>(tz: Tz) -> AsyncScheduler<Tz>[src]

Create a new scheduler. Dates and times will be interpretted using the specified timezone.

pub fn with_tz_and_provider<Tz: TimeZone, Tp: TimeProvider>(
    tz: Tz
) -> AsyncScheduler<Tz, Tp>
[src]

Create a new scheduler. Dates and times will be interpretted using the specified timezone. In addition, you can provide an alternate time provider. This is mostly useful for writing tests.

impl<Tz, Tp> AsyncScheduler<Tz, Tp> where
    Tz: TimeZone + Sync + Send,
    Tp: TimeProvider
[src]

pub fn every(&mut self, ival: Interval) -> &mut AsyncJob<Tz, Tp>[src]

Add a new job to the scheduler to be run on the given interval

let mut scheduler = AsyncScheduler::new();
scheduler.every(10.minutes()).plus(30.seconds()).run(|| async { println!("Periodic task") });
scheduler.every(1.day()).at("3:20 pm").run(|| some_async_fn());
scheduler.every(Wednesday).at("14:20:17").run(|| Pin::from(returns_boxed_future()));
scheduler.every(Weekday).run(|| returns_pinned_boxed_future());

pub fn run_pending(&mut self) -> AsyncSchedulerFuture[src]

Run all jobs that should run at this time.

This method returns a future that will poll each of the tasks until they are completed.

use std::time::Duration;
loop {
    scheduler.run_pending().await;
    tokio::time::sleep(Duration::from_millis(100)).await;
}

Note that while all pending jobs will run asynchronously, a long-running task can still block future executions if you await the future returned by this method. If you are concerned that a task might run for a long time, there are several possible approaches:

  1. Pass the result of scheduler.run_pending() to your runtime’s spawn function. This might result in multiple invocations of the same task running concurrently.
  2. Use spawn or spawn_blocking in your task itself. This has the same concurrent execution risk as approach 1, but limited to that specific task.
  3. Use tokio::time::timeout or equivalent to prevent scheduler.run_pending() or the task itself from running more than an expected amount of time. E.g.
use std::time::Duration;
let mut scheduler = AsyncScheduler::new();
scheduler.every(10.minutes()).run(|| async {
  if let Err(_) = tokio::time::timeout(Duration::from_secs(10 * 60), scrape_pages()).await {
    eprintln!("Timed out scraping pages")
  }
});

Trait Implementations

impl<Tz: Debug, Tp: Debug> Debug for AsyncScheduler<Tz, Tp> where
    Tz: TimeZone,
    Tp: TimeProvider
[src]

impl Default for AsyncScheduler[src]

Auto Trait Implementations

impl<Tz = Local, Tp = ChronoTimeProvider> !RefUnwindSafe for AsyncScheduler<Tz, Tp>

impl<Tz, Tp> Send for AsyncScheduler<Tz, Tp> where
    Tp: Send,
    Tz: Send,
    <Tz as TimeZone>::Offset: Send

impl<Tz = Local, Tp = ChronoTimeProvider> !Sync for AsyncScheduler<Tz, Tp>

impl<Tz, Tp> Unpin for AsyncScheduler<Tz, Tp> where
    Tp: Unpin,
    Tz: Unpin,
    <Tz as TimeZone>::Offset: Unpin

impl<Tz = Local, Tp = ChronoTimeProvider> !UnwindSafe for AsyncScheduler<Tz, Tp>

Blanket Implementations

impl<T> Any for T where
    T: 'static + ?Sized
[src]

impl<T> Borrow<T> for T where
    T: ?Sized
[src]

impl<T> BorrowMut<T> for T where
    T: ?Sized
[src]

impl<T> From<T> for T[src]

impl<T, U> Into<U> for T where
    U: From<T>, 
[src]

impl<T, U> TryFrom<U> for T where
    U: Into<T>, 
[src]

type Error = Infallible

The type returned in the event of a conversion error.

impl<T, U> TryInto<U> for T where
    U: TryFrom<T>, 
[src]

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.