|
| 1 | +@author Francesca Gangemi < [email protected]> |
| 2 | +@author Ulf Wiger < [email protected]> |
| 3 | + |
| 4 | +@doc The Ecron application |
| 5 | + |
| 6 | +The Ecron application executes scheduled functions. |
| 7 | +A list of functions to execute might be specified in the ecron application |
| 8 | +resource file as value of the `scheduled' environment variable. |
| 9 | + |
| 10 | +Each entry specifies a job and must contain the scheduled time and a MFA |
| 11 | +tuple `{Module, Function, Arguments}'. |
| 12 | +It's also possible to configure options for a retry algorithm to run in case |
| 13 | +MFA fails. |
| 14 | +<pre> |
| 15 | +Job = {{Date, Time}, MFA, Retry, Seconds} | |
| 16 | + {{Date, Time}, MFA} |
| 17 | +</pre> |
| 18 | +`Seconds = integer()' is the retry interval. |
| 19 | + |
| 20 | +`Retry = integer() | infinity' is the number of times to retry. |
| 21 | + |
| 22 | + |
| 23 | +Example of ecron.app |
| 24 | +<pre> |
| 25 | +... |
| 26 | +{env,[{scheduled, |
| 27 | + [{{{ '*', '*', '*'}, {0 ,0,0}}, {my_mod, my_fun1, Args}}, |
| 28 | + {{{ '*', 12 , 25}, {0 ,0,0}}, {my_mod, my_fun2, Args}}, |
| 29 | + {{{ '*', 1 , 1 }, {0 ,0,0}}, {my_mod, my_fun3, Args}, infinity, 60}, |
| 30 | + {{{2010, 1 , 1 }, {12,0,0}}, {my_mod, my_fun3, Args}}, |
| 31 | + {{{ '*', 12 ,last}, {0 ,0,0}}, {my_mod, my_fun4, Args}]}]}, |
| 32 | +... |
| 33 | +</pre> |
| 34 | +Once the ecron application is started, it's possible to dynamically add new |
| 35 | +jobs using the `ecron:insert/2' or `ecron:insert/4' |
| 36 | +API. |
| 37 | + |
| 38 | +The MFA is executed when a task is set to run. |
| 39 | +The MFA has to return `ok', `{ok, Data}', `{apply, fun()}' |
| 40 | +or `{error, Reason}'. |
| 41 | +If `{error, Reason}' is returned and the job was defined with retry options |
| 42 | +(Retry and Seconds were specified together with the MFA) then ecron will try |
| 43 | +to execute MFA later according to the given configuration. |
| 44 | + |
| 45 | +The MFA may return `{apply, fun()}' where `fun()' has arity zero. |
| 46 | + |
| 47 | +`fun' will be immediately executed after MFA execution. |
| 48 | +The `fun' has to return `ok', `{ok, Data}' or `{error, Reason}'. |
| 49 | + |
| 50 | +If the MFA or `fun' terminates abnormally or returns an invalid |
| 51 | +data type (not `ok', `{ok, Data}' or `{error, Reason}'), an event |
| 52 | +is forwarded to the event manager and no retries are executed. |
| 53 | + |
| 54 | +If the return value of the fun is `{error, Reason}' and retry |
| 55 | +options were given in the job specification then the `fun' is |
| 56 | +rescheduled to be executed after the configurable amount of time. |
| 57 | + |
| 58 | +Data which does not change between retries of the `fun' |
| 59 | +must be calculated outside the scope of the `fun'. |
| 60 | +Data which changes between retries has to be calculated within the scope |
| 61 | +of the `fun'.<br/> |
| 62 | +In the following example, ScheduleTime will change each time the function is |
| 63 | +scheduled, while ExecutionTime will change for every retry. If static data |
| 64 | +has to persist across calls or retries, this is done through a function in |
| 65 | +the MFA or the fun. |
| 66 | + |
| 67 | +<pre> |
| 68 | +print() -> |
| 69 | + ScheduledTime = time(), |
| 70 | + {apply, fun() -> |
| 71 | + ExecutionTime = time(), |
| 72 | + io:format("Scheduled:~p~n",[ScheduledTime]), |
| 73 | + io:format("Execution:~p~n",[ExecutionTime]), |
| 74 | + {error, retry} |
| 75 | + end}. |
| 76 | +</pre> |
| 77 | +Event handlers may be configured in the application resource file specifying |
| 78 | +for each of them, a tuple as the following: |
| 79 | + |
| 80 | +<pre>{Handler, Args} |
| 81 | + |
| 82 | +Handler = Module | {Module,Id} |
| 83 | +Module = atom() |
| 84 | +Id = term() |
| 85 | +Args = term() |
| 86 | +</pre> |
| 87 | +`Module:init/1' will be called to initiate the event handler and |
| 88 | +its internal state<br/><br/> |
| 89 | +Example of ecron.app |
| 90 | +<pre> |
| 91 | +... |
| 92 | +{env, [{event_handlers, [{ecron_event, []}]}]}, |
| 93 | +... |
| 94 | +</pre> |
| 95 | +The API `add_event_handler/2' and |
| 96 | +`delete_event_handler/1' |
| 97 | +allow user to dynamically add and remove event handlers. |
| 98 | + |
| 99 | +All the configured event handlers will receive the following events: |
| 100 | + |
| 101 | +`{mfa_result, Result, {Schedule, {M, F, A}}, DueDateTime, ExecutionDateTime}' |
| 102 | + when MFA is executed. |
| 103 | + |
| 104 | +`{fun_result, Result, {Schedule, {M, F, A}}, DueDateTime, ExecutionDateTime}' |
| 105 | +when `fun' is executed. |
| 106 | + |
| 107 | +`{retry, {Schedule, MFA}, Fun, DueDateTime}' |
| 108 | +when MFA, or `fun', is rescheduled to be executed later after a failure. |
| 109 | + |
| 110 | +`{max_retry, {Schedule, MFA}, Fun, DueDateTime}' when MFA, |
| 111 | +or `fun' has reached maximum number of retry specified when |
| 112 | +the job was inserted. |
| 113 | + |
| 114 | +`Result' is the return value of MFA or `fun'. |
| 115 | + If an exception occurs during evaluation of MFA, or `fun', then |
| 116 | +it's caught and sent in the event. |
| 117 | +(E.g. <code>Result = {'EXIT',{Reason,Stack}}</code>). |
| 118 | + |
| 119 | +`Schedule = {Date, Time}' as given when the job was inserted, E.g. |
| 120 | +<code> {{'*','*','*'}, {0,0,0}}</code><br/> |
| 121 | +`DueDateTime = {Date, Time} ' is the exact Date and Time when the MFA, |
| 122 | +or the `fun', was supposed to run. |
| 123 | + E.g. ` {{2010,1,1}, {0,0,0}}'<br/> |
| 124 | +`ExecutionDateTime = {Date, Time} ' is the exact Date and Time |
| 125 | +when the MFA, or the `fun', was executed.<br/><br/><br/> |
| 126 | +If a node is restarted while there are jobs in the list then these jobs are |
| 127 | +not lost. When Ecron starts it takes a list of scheduled MFA from the |
| 128 | +environment variable `scheduled' and inserts them into a persistent table |
| 129 | +(mnesia). If an entry of the scheduled MFA specifies the same parameters |
| 130 | +values of a job already present in the table then the entry won't be inserted |
| 131 | +avoiding duplicated jobs. <br/> |
| 132 | +No duplicated are removed from the MFA list configured in the ` |
| 133 | +scheduled' variable. |
| 134 | + |
| 135 | +<pre> |
| 136 | +Copyright (c) 2009-2011 Erlang Solutions Ltd |
| 137 | +All rights reserved. |
| 138 | + |
| 139 | +Redistribution and use in source and binary forms, with or without |
| 140 | +modification, are permitted provided that the following conditions are met: |
| 141 | +* Redistributions of source code must retain the above copyright |
| 142 | + notice, this list of conditions and the following disclaimer. |
| 143 | +* Redistributions in binary form must reproduce the above copyright |
| 144 | + notice, this list of conditions and the following disclaimer in the |
| 145 | + documentation and/or other materials provided with the distribution. |
| 146 | +* Neither the name of the Erlang Solutions nor the names of its |
| 147 | + contributors may be used to endorse or promote products |
| 148 | + derived from this software without specific prior written permission. |
| 149 | + |
| 150 | +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
| 151 | +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| 152 | +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
| 153 | +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS |
| 154 | +BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
| 155 | +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
| 156 | +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR |
| 157 | +BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, |
| 158 | +WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR |
| 159 | +OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF |
| 160 | +ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 161 | +</pre> |
| 162 | + |
| 163 | +@end |
0 commit comments