How can I run a cron scheduled task in Mathematica?

For a simple schedule you can use build-in RunScheduledTask. For example, the following will print current time if the number of seconds is multiple of 10

RunScheduledTask[Print@Now, 10, Ceiling[AbsoluteTime[], 10]]

enter image description here

RemoveScheduledTask[ScheduledTasks[]];

Using the quartz library implemented in Java we can have access to the next execution date of a scheduled task given a cron specification. Then the code below creates a scheduled task that executes at the next execution date and extends itself after the task has been executed.

Other helper functions are provided.

You can download the quartz library at the direct download of this page https://quartz-scheduler.org/downloads and for the code below to run you need to extract the Jar library located at lib\quartz-2.2.2.jar in the downloaded file.

Exemple

You need first to access the quartz jar

Needs["JLink`"];
InstallJava[];
AppendTo[JLink`$ExtraClassPath,pathOfTheQuartzJarDirectory];

The cron specs below are trivial, but this is just an example. Any cron specification works.

cronSpecs="* * * ? * MON-SUN";
x=CreateCronScheduledTask[Print@DateString[],cronSpecs];
StartScheduledTask@x

StopScheduledTask@x;

x=RunCronScheduledTask[Print@DateString[],cronSpecs]

Code

(*http://www.quartz-scheduler.org/documentation/quartz-1.x/tutorials/crontrigger*)
(*for multiple triggers in a same specs, triggers are separated by "//"*)
NextCronExecutionDate[cronSpecs_ /; StringContainsQ[cronSpecs,"//"],currentDate_:Automatic]:=
    NextCronExecutionDate[#,currentDate]& /@ StringSplit[cronSpecs,"//"] //
    DeleteCases[_Missing]//
    If[#==={},
        Missing["NextCronDate",cronSpecs]
        ,
        Sort[#,LexicographicOrderedQ]//First
    ]&;

NextCronExecutionDate[cronSpecs_,currentDate_:Automatic]:=
    JavaBlock@Module[{cronExpr,date,javaDate},

        date=DateList@If[currentDate===Automatic,##&[],currentDate];
        date[[1]] -= 1900;
        date[[2]] -= 1;
        date[[-1]] = Round[date[[-1]]];

        javaDate = JavaNew["java.util.Date",##]& @@ date;
        cronExpr = JavaNew["org.quartz.CronExpression",cronSpecs];

        cronExpr@getNextValidTimeAfter[javaDate]//
        If[#===Null,
            Missing["NextCronDate",cronSpecs]
            ,
            #@toString[]//DateList
        ]&
    ];
(*NextCronExecutionDate["0 15 10 ? * MON-FRI"]*)

(*works for positive numbers, we consider that {1}=={1,0}<={1,1}*)  
LexicographicOrderedQ[{},_]:=True;
LexicographicOrderedQ[_,{}]:=False;
LexicographicOrderedQ[l1_,l2_]:= First@l1<First@l2 || (First@l1==First@l2 && LexicographicOrderedQ[Rest@l1,Rest@l2]);

SetAttributes[createOrRunCronScheduledTask,HoldFirst];
createOrRunCronScheduledTask[action_,cronSpecs_,create_:True]:=
    NextCronExecutionDate@cronSpecs //
        If[Head@#=!=Missing,
            If[create,CreateScheduledTask,RunScheduledTask][

                action;

                NextCronExecutionDate@cronSpecs //
                    If[Head@#=!=Missing,
                        ResetScheduledTask[$ScheduledTask,{0},AbsoluteTime@#];
			StartScheduledTask@$ScheduledTask;
                    ]&;
                ,
                {0},AbsoluteTime@#
            ] //
            CronScheduledTaskObject[#,cronSpecs]&
            ,
            #
        ]&;

(*We could also overload CreateScheduledTask and RunScheduledTask for a string specification*)
SetAttributes[CreateCronScheduledTask,HoldFirst];
CreateCronScheduledTask[action_,cronSpecs_]:=createOrRunCronScheduledTask[action,cronSpecs,True];

SetAttributes[RunCronScheduledTask,HoldFirst];
RunCronScheduledTask[action_,cronSpecs_]:=createOrRunCronScheduledTask[action,cronSpecs,False];

CronScheduledTaskObject /: StartScheduledTask[cronScheduledTask_CronScheduledTaskObject]:=
    NextCronExecutionDate@cronScheduledTask[[2]] //
        If[Head@#=!=Missing,
            ResetScheduledTask[cronScheduledTask[[1]],{0},AbsoluteTime@#];
            StartScheduledTask@cronScheduledTask[[1]];

            cronScheduledTask
            ,
            #
        ]&;

CronScheduledTaskObject /: StopScheduledTask[cronScheduledTask_CronScheduledTaskObject]:= 
    (
        StopScheduledTask@cronScheduledTask[[1]];
        cronScheduledTask
    );

CronScheduledTaskObject /: ResetScheduledTask[cronScheduledTask_CronScheduledTaskObject,newCronSpecs_]:= 
    (
        StopScheduledTask@cronScheduledTask;
        CronScheduledTaskObject[cronScheduledTask[[1]],newCronSpecs]
    );

CronScheduledTaskObject /: RemoveScheduledTask[cronScheduledTask_CronScheduledTaskObject]:= 
    (
        RemoveScheduledTask@First@cronScheduledTask;
        cronScheduledTask
    );

Tags:

Scheduling