Struct clokwerk::AsyncScheduler
source · pub struct AsyncScheduler<Tz = Local, Tp = ChronoTimeProvider>where
Tz: TimeZone,
Tp: TimeProvider,{ /* private fields */ }
Expand description
An asynchronous job scheduler, for use with Future
s.
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
sourceimpl AsyncScheduler
impl AsyncScheduler
sourcepub fn new() -> Self
pub fn new() -> Self
Create a new scheduler. Dates and times will be interpretted using the local timezone
sourcepub fn with_tz<Tz: TimeZone>(tz: Tz) -> AsyncScheduler<Tz>
pub fn with_tz<Tz: TimeZone>(tz: Tz) -> AsyncScheduler<Tz>
Create a new scheduler. Dates and times will be interpretted using the specified timezone.
sourcepub fn with_tz_and_provider<Tz: TimeZone, Tp: TimeProvider>(
tz: Tz
) -> AsyncScheduler<Tz, Tp>
pub fn with_tz_and_provider<Tz: TimeZone, Tp: TimeProvider>(
tz: Tz
) -> AsyncScheduler<Tz, Tp>
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.
sourceimpl<Tz, Tp> AsyncScheduler<Tz, Tp>where
Tz: TimeZone + Sync + Send,
Tp: TimeProvider,
impl<Tz, Tp> AsyncScheduler<Tz, Tp>where
Tz: TimeZone + Sync + Send,
Tp: TimeProvider,
sourcepub fn every(&mut self, ival: Interval) -> &mut AsyncJob<Tz, Tp>
pub fn every(&mut self, ival: Interval) -> &mut AsyncJob<Tz, Tp>
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());
sourcepub fn run_pending(&mut self) -> AsyncSchedulerFuture
pub fn run_pending(&mut self) -> AsyncSchedulerFuture
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:
- Pass the result of
scheduler.run_pending()
to your runtime’sspawn
function. This might result in multiple invocations of the same task running concurrently. - Use
spawn
orspawn_blocking
in your task itself. This has the same concurrent execution risk as approach 1, but limited to that specific task. - Use
tokio::time::timeout
or equivalent to preventscheduler.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")
}
});