homeparametricParametricScheduler
search
search
ParametricScheduler

parametric scheduler

ParametricScheduler is used to schedule recurring and one-time tasks from Julia. This fills the role of applications like Crontab in systems applications, only in this case facilitated through Julia and its Dates Module. These tasks can also be scaled using multi-threading and ParametricProcesses.

  • installation is done using Pkg:

using Pkg; Pkg.add("ParametricScheduler")

Alternatively, add Unstable for the latest development updates that may occassionally be broken:

using Pkg; Pkg.add(name = "ParametricScheduler", rev = "Unstable")

configuration files

ParametricScheduler is primarily intended for use through configuration files. This package has its own unique formatting for .cfg files that are relatively straightforward to configure. Each Task is represented by a line inside of our .cfg file — missing lines and lines starting with comments are an exception, as are some other special lines. Each Task line will start with a number, and this number tells the reader how that task should be read. Lines starting with a # will be ignored, and lines can also call include, using, and activate in very specific ways. There are four different task types:

  • 0 A DateTime task,

  • 1 a recurring DateTime task,

  • 2 an immediate task,

  • and 3: A recurring immediate task.

For 0 and 1, we start by providing the datetime associated with the command. These are 7 unique and ordered numbers, representing

    1. Year

    2. Month

    3. Day

    4. Hour

    5. Minute

    6. Second

    7. Millisecond

For example, the following is at 5 in February, 2025:

# v 0 means datetime task
0 2025 2 1 5 0 1 0

following this is - and the command and arguments. The arguments are separated from the command by another space, and separated from eachother using a -.

0 2025 2 1 5 0 1 0 - println "hello"-"hi"-"hola"

Argument types are somewhat limited, arguments are only parsed as floats, integers, commands, and strings. As for recurring events, they are very similar but also feature two additional numbers alongside the command.

1 _ _ _ _ _ _ _ - _ _ cmd args-...

These two additional values represent the type of interval and the interval. For the type, we use the same number classification from before:

    1. Year

    2. Month

    3. Day

    4. Hour

    5. Minute

    6. Second

    7. Millisecond

For example, thirty seconds from our aforementioned date:

1 2025 2 1 5 0 1 0 - 6 30 sum 5-6

The codes two and three remove the dates from the beginning, and will set the date of the task to now — performing the task immediately on startup, and if recurring recurring from there. 2 is non-recurring and 3 is recurring.

# 2 = do immediately...

2 cmd args-

# 3 = do recurringly at x interval

3 _ _ cmd args ...

Configuration files also have the ability to load modules into mod for multi-threading; when using functions and modules across multiple threads, it will be essential that we use those modules or include them from files before starting.

We load in our dependencies using activate, using, and include lines.

# sample config
# activates our environment
activate .
# loads Pkg 
using Pkg
# loads `fns.jl`, containing `sampletwo`
include fns.jl
# every 7 seconds
3 6 7 sampletwo "hi! I am running!"
2 sampletwo "immediately runs"
# every 24 hours from now, as well as right now
3 4 24 Pkg.instantiate

To start this, we provide our configuration file's path to ParametricScheduler.start. This will return a Scheduler based on our configuration.

start(path::String = pwd() * "config.cfg", threads::Integer = 1, async::Bool = 1-> ::Scheduler

To start directly from the command line:

julia -e 'using ParametricScheduler; ParametricScheduler.start("config.cfg")'

time

start(scheduler::Scheduler, mods::Any ...; threads::Int64 = 1, async::Bool = true)
start(t::Task ..., args ...; keyargs ...)
start(path::String = pwd() * "config.cfg", mods::Any ...; keyargs ...)

Though ParametricScheduler is primarily intended for use from configuration files, it is possible to schedule tasks using the API. We start by creating our time type, which will be either DateTime or RecurringTime. For a DateTime, we provide the same seven values we mentioned before.

ParametricScheduler exports Method and structs for these intervals, e.g. Year and year. Year would be used to construct a Year interval and year would be used to get the year from a DateTime. ParametricScheduler exports all of these. These constructed intervals will be provided to RecurringTime, or can be used arithmetically with DateTime.

using ParametricScheduler
# one year from now
= now() * Year(1)
# every year from now on
my_time = RecurringTime(now(), Year(1))

# getter example:
minute_of_now::Int64 = minute(d)

For getters, we simply call the getter on our DateTime.

using ParametricScheduler
# 5 A.M. on the first of January, 2025
my_time = DateTime(2025115000)

To create a RecurringTime, we provide a start time (another DateTime) and an interval from that start time.

#                                                (every hour)
my_time = RecurringTime(DateTime(2025115000), Hour(1))

tasks

After creating a time, we call new_task to create a task from that time.

new_task(f::Function, t::Any, args ...; keyargs ...)
my_task = new_task(println, now(), "hello scheduler!")

scheduler

Now we can provide this new task to Scheduler to create a new Scheduler, or we could provide these tasks directly to start and get a started Scheduler in return. When we choose the former, we still need to call start on the Scheduler to start its process.

unstarted_sched = Scheduler(my_task)

started_sched 
= ParametricScheduler.start(my_task)

started_sched2 
= ParametricScheduler.start(unstarted_sched)

There is also add_tasks! and remove_task!. add_tasks! works as expected, all tasks are provided (not as a Vector) directly to this function. remove_task! can remove tasks by date or enumeration. The tasks are available via Scheduler.jobs.

remove_task!(sched::Scheduler, date::Dates.DateTime)
remove_task!(sched::Scheduler, num::Int64)
add_tasks!(sched::Scheduler, tasks::Task ...)

Finally, to close our scheduler we use close(::Scheduler).

close(started_sched)
close(started_sched2)

We can also save a scheduler to a file using save_config or read tasks directly from a file using start.

It is assumed that all assigned functions will be loaded into Main; this means including your functions before assigning them as jobs and distributing them. When it comes to multi-threading, we use mod arguments to include our functions. This may be done from a configuration file or provided as arguments. Threads will not be able to run functions that are not loaded by provided the Module or include path to mods.

  • mods in configuration file:

activate .
using Pkg
include fns.jl
3 6 7 sampletwo "hi1"
3 6 4 sampletwo "hi2"
3 4 24 Pkg.instantiate
  • mods in API:

using ParametricScheduler
using TOML
# make sure to also include on the main thread (if not, you will get a failed to run task warning):
include("fns.jl")
# the `mods` key-word argument is specific to this dispatch.
ParametricScheduler.start(sched, new_task(println, now(), "hello scheduler!"), mods = ["fns.jl", TOML] threads = 4)

internal bindings

There are a few internal bindings that are not mentioned in this overview. Here are some doc-strings:

happy scheduling!

chifidocs is currently offline; you are viewing a cached version of the site. Some functionality might be missing. Click this message to try for a live version of chifidocs again.