14
$\begingroup$

Mathematica doesn't have a built-in Cron scheduler. How can I use scheduled tasks in order to implement one ?

$\endgroup$
2
  • $\begingroup$ why dont you just use cron rather than leave mathematica running all the time to do that job? $\endgroup$
    – george2079
    Commented Nov 8, 2015 at 2:20
  • 2
    $\begingroup$ Because I need the code executed by the scheduled task to have access to the variables of the current session. It's not an independent script running with cron. $\endgroup$
    – faysou
    Commented Nov 8, 2015 at 9:17

2 Answers 2

7
$\begingroup$

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[]];
$\endgroup$
0
6
$\begingroup$

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
    );
$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.