Mathematica doesn't have a built-in Cron scheduler. How can I use scheduled tasks in order to implement one ?
-
$\begingroup$ why dont you just use cron rather than leave mathematica running all the time to do that job? $\endgroup$– george2079Commented 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$– faysouCommented Nov 8, 2015 at 9:17
2 Answers
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]]
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
);