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

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

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

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

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.

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());

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

Formats the value using the given formatter. Read more
Returns the “default value” for a type. Read more

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more
Immutably borrows from an owned value. Read more
Mutably borrows from an owned value. Read more

Returns the argument unchanged.

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

The type returned in the event of a conversion error.
Performs the conversion.
The type returned in the event of a conversion error.
Performs the conversion.