Scheduling Tasks in D
Written by Andrew Lalis at 22 September, 2021
A quick look at scheduled, a scheduling library for D.
For those coming from Java, you may be familiar with Quartz Scheduler, a library for scheduling and executing tasks to run at specific times, using simple schedules or even powerful Cron-style expressions. Or you might already be familiar with cron
program itself, for scheduling tasks to run in Unix systems.
Since recently discovering the hidden gem that is the D programming language, I've been wanting a scheduling library to make running scheduled tasks as easy as with Java. Introducing scheduled, a very simple library that gives you the ability to run tasks according to pre-defined schedules.
For starters, here's a minimal example:
import std.stdio;
import core.time;
import std.datetime;
import scheduled; // Import our library.
void main() {
JobScheduler scheduler = new ThreadedJobScheduler;
scheduler.addJob(
() => writeln("Executing at " ~ Clock.currTime.toISOExtString),
new FixedIntervalSchedule(seconds(12))
);
scheduler.start();
}
As you can probably see, scheduled consists of three main components: the scheduler, the schedule, and the job to execute. Schedulers, when started, will execute any jobs they have been given, according to the schedule associated with each job.
In addition to the FixedIntervalSchedule
from our example, the following other schedules are available:
new OneTimeSchedule(Clock.currTime + minutes(10))
Executes a job once, at a specific time. Here, we say that the job should be executed exactly 10 minutes after the current time.new DailySchedule(TimeOfDay(12, 35, 0), TimeOfDay(6, 44, 2))
Executes a job each day, at every specified time. Here, we're saying that jobs should be executed at 12:35:00, and at 6:44:02.new CronSchedule("0 */5 * * * MON,FRI")
Executes a job according to a Cron expression. In this case, jobs with this schedule will be executed every 5 minutes, on Monday and Friday. A special thanks to Maxim Tyapkin for his work on cronexp, a library which scheduled uses to parse and evaluate Cron expressions.
By default, scheduled includes one implementation of the interface JobScheduler
, and that is the ThreadedJobScheduler
, as was shown in the example.
The threaded scheduler runs as a single thread when started, and keeps all its jobs in a priority queue, ordered so that the first item is the job that is scheduled to execute the soonest. The scheduler will periodically get the first job from its queue, then sleep until it's time to execute that job, at which point it'll hand off the job to a TaskPool to actually execute the job's public void run()
method. The scheduler then fetches the next job in the queue, and starts the whole process over again.
Next Steps
Now that we've got a basic scheduling implementation, the next goals are:
- Allow persistent job storage, so that the program can reboot, and pick up right where it left off.
- More advanced scheduler implementations, that allow adding and removing jobs during runtime.
- Distributed job execution: let a scheduler distribute the execution of jobs to different machines, either by preference or automatically balancing the load.
If you think that you could help with any of these goals, head over to the scheduled repository on GitHub and make a pull request!