Skip to content

Commit

Permalink
Merge pull request #11 from zhongwencool/refactor
Browse files Browse the repository at this point in the history
Refactor
  • Loading branch information
zhongwencool authored Mar 9, 2021
2 parents 8b21a20 + da30336 commit b3c6dce
Show file tree
Hide file tree
Showing 26 changed files with 1,731 additions and 1,331 deletions.
47 changes: 43 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ You can find a collection of general practices in [Full Erlang Examples](https:/
```elixir
# mix.exs
def deps do
[{:ecron, "~> 0.5"}]
[{:ecron, "~> 0.6"}]
end
```

Expand All @@ -63,8 +63,8 @@ You can find a collection of general practices in [Full Erlang Examples](https:/
{extend_crontab_job, "0 0 1-6/2,18 * * *", {io, format, ["Runs on 1,3,6,18 o'clock:~n"]}},
{alphabet_job, "@hourly", {io, format, ["Runs every(0-23) o'clock~n"]}},
{fixed_interval_job, "@every 30m", {io, format, ["Runs every 30 minutes"]}},
%% Runs 0-23 o'clock since {{2019,9,26},{0,0,0}}.
{limit_datetime_job, "@hourly", {io, format, ["Runs every(0-23) o'clock~n"]}, {{2019,9,26},{0,0,0}}, unlimited},
%% Runs every 15 minutes between {8,20,0} and {23, 59, 59}.
%% {limit_time_job, "*/15 * * * *", {io, format, ["Runs 0, 15, 30, 45 minutes after 8:20am~n"]}, {8,20,0}, unlimited}
%% parallel job
{no_singleton_job, "@minutely", {timer, sleep, [61000]}, unlimited, unlimited, [{singleton, false}]}
]},
Expand All @@ -84,6 +84,45 @@ You can find a collection of general practices in [Full Erlang Examples](https:/
You can also reload task manually by `ecron:reload().` when the system time is manually modified.
* Global jobs depend on [global](http://erlang.org/doc/man/global.html), only allowed to be added statically, [check this for more detail](https://github.com/zhongwencool/ecron/blob/master/doc/global.md).

## Supervisor Tree Usage
Ecron starts with a standalone process(`ecron_local`) to manage all jobs by default,
but you can also set up your own job management process for each application,
which has the advantage that you can precisely control its start time and stop timing.
This has the advantage that you can precisely control when it starts and when it stops.
The Jobs between various applications do not affect each other.

Ecron must be included in your application's supervision tree.
All of your configuration is passed into the supervisor:
```erlang
%%config/sys.config
[{your_app, [{crontab_jobs, [
{crontab_job, "*/15 * * * *", {stateless_cron, inspect, ["Runs on 0, 15, 30, 45 minutes"]}}
]}
].
%% src/your_app_sup.erl
-module(your_app_top_sup).
-behaviour(supervisor).
-export([init/1]).
init(_Args) ->
Jobs = application:get_env(your_app, crontab_jobs, []),
SupFlags = #{
strategy => one_for_one,
intensity => 100,
period => 30
},
Name = 'uniqueName',
CronSpec = #{
id => Name,
start => {ecron, start_link, [Name, Jobs]},
restart => permanent,
shutdown => 1000,
type => worker
},
{ok, {SupFlags, [CronSpec]}}.
```
## Advanced Usage
```erlang
Expand Down Expand Up @@ -275,7 +314,7 @@ For example, "@every 1h30m10s" would indicate a schedule that activates after 1
>Note: The interval doesn't take the job runtime into account.
>For example, if a job takes 3 minutes to run, and it is scheduled to run every 5 minutes,
>it also has 5 minutes of idle time between each run.
>it only has 2 minutes of idle time between each run.
## Test
Expand Down
26 changes: 13 additions & 13 deletions examples/titan_elixir/apps/titan/lib/titan/stateless_cron.ex
Original file line number Diff line number Diff line change
Expand Up @@ -10,24 +10,24 @@ defmodule StatelessCron do
end

## Add job run at At minute 23 past every 2nd hour from 0 through 20
## between {{2020, 1, 1}, {0, 0, 0}} and {{2022, 1, 1}, {0, 0, 0}}
## by ecron:add_with_datetime / 4
def add_limited_start_end_datetime_job2() do
## between {12, 0, 0} and {18, 0, 0}
## by ecron:add_with_datetime / 5
def add_limited_start_end_time_job2() do
mfa = {__MODULE__, :inspect, ["at minute 23 past every 2nd hour from 0 through 20."]}
start_time = {{2020, 1, 1}, {0, 0, 0}} #datetime or `unlimited`
end_time = {{2022, 1, 1}, {0, 0, 0}} # datetime or `unlimited`
:ecron.add_with_datetime("0 23 0-20/2 * * *", mfa, start_time, end_time)
start_time = {12, 0, 0} #datetime or `unlimited`
end_time = {18, 0, 0} # datetime or `unlimited`
:ecron.add_with_time(make_ref(), "0 23 0-20/2 * * *", mfa, start_time, end_time)
end

## Add job run at 14:15 on day-of-month 1
##between {{2020, 1, 1}, {0, 0, 0}} and {{2022, 1, 1}, {0, 0, 0}}
##between {{11, 0, 0}} and {{22, 10, 0}}
## by ecron:add_with_datetime / 5
def add_limited_start_end_datetime_job() do
def add_limited_start_end_time_job() do
job_name = :limited_start_end_datetime_cron_job
mfa = {__MODULE__, :inspect, ["at 14:15 on day-of-month 1."]}
start_time = {{2020, 1, 1}, {0, 0, 0}} # datetime or `unlimited`
end_time = {{2022, 1, 1}, {0, 0, 0}} # datetime or `unlimited`
{:ok, ^job_name} = :ecron.add_with_datetime(job_name, "0 15 14 1 * *", mfa, start_time, end_time)
mfa = {__MODULE__, :inspect, ["at 14~23:15 on day-of-month 1."]}
start_time = {11, 0, 0} # time or `unlimited`
end_time = {22, 10, 0} # time or `unlimited`
{:ok, ^job_name} = :ecron.add_with_time(job_name, "0 15 14-23 1 * *", mfa, start_time, end_time)
end

## Can only run 100 times at 22:00 on every day-of-week from Monday through Friday.
Expand All @@ -42,7 +42,7 @@ defmodule StatelessCron do
def add_limited_run_count_job2() do
mfa = {__MODULE__, :inspect, ["at minute 0 past hour 0 and 12 on day-of-month 1 in every 2nd month."]}
job_name = :limited_run_count_cron_job
:ecron.add_with_count(job_name, "0 22 * * 1-5", mfa, 100)
:ecron.add_with_count(:ecron_job, job_name, "0 22 * * 1-5", mfa, 100)
end

## Delete a specific task
Expand Down
2 changes: 1 addition & 1 deletion examples/titan_elixir/config/config.exs
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ config :ecron, :local_jobs,
:limit_datetime_job,
"@hourly",
{StatelessCron, :inspect, ["Runs every(0-23) o'clock"]},
{{2019, 9, 26}, {0, 0, 0}},
{11, 0, 0},
:unlimited
},
# Job with max run count, default is `unlimited`
Expand Down
36 changes: 18 additions & 18 deletions examples/titan_erlang/apps/titan/src/stateless_cron.erl
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@

%% API
-export([add_every_4am_job/0]).
-export([add_limited_start_end_datetime_job/0]).
-export([add_limited_start_end_datetime_job2/0]).
-export([add_limited_start_end_time_job/0]).
-export([add_limited_start_end_time_job2/0]).
-export([add_limited_run_count_job/0]).
-export([add_limited_run_count_job2/0]).
-export([delete_job/1]).
Expand All @@ -20,23 +20,23 @@ add_every_4am_job() ->
{ok, JobName} = ecron:add(JobName, "0 4 * * *", MFA).

%% Add job run at At minute 23 past every 2nd hour from 0 through 20
%% between {{2020, 1, 1}, {0, 0, 0}} and {{2022, 1, 1}, {0, 0, 0}}
%% by ecron:add_with_datetime/4
add_limited_start_end_datetime_job2() ->
%% between {10, 0, 0} and {23, 59, 59}
%% by ecron:add_with_time/5
add_limited_start_end_time_job2() ->
MFA = {?MODULE, inspect, ["at minute 23 past every 2nd hour from 0 through 20."]},
Start = {{2020, 1, 1}, {0, 0, 0}}, %% datetime or `unlimited`
End = {{2022, 1, 1}, {0, 0, 0}}, %% datetime or `unlimited`
ecron:add_with_datetime("0 23 0-20/2 * * *", MFA, Start, End).

%% Add job run at 14:15 on day-of-month 1
%% between {{2020, 1, 1}, {0, 0, 0}} and {{2022, 1, 1}, {0, 0, 0}}
%% by ecron:add_with_datetime/5
add_limited_start_end_datetime_job() ->
Start = {{10, 0, 0}}, %% time or `unlimited`
End = unlimited, %% time or `unlimited`
ecron:add_with_time(make_ref(), "0 23 0-20/2 * * *", MFA, Start, End).

%% Add job run at 14~23:00-15-30-45 on day-of-month 1
%% between {10, 0, 0} and {22, 0, 0}
%% by ecron:add_with_time/5
add_limited_start_end_time_job() ->
JobName = limited_start_end_datetime_cron_job,
MFA = {?MODULE, inspect, ["at 14:15 on day-of-month 1."]},
Start = {{2020, 1, 1}, {0, 0, 0}}, %% datetime or `unlimited`
End = {{2022, 1, 1}, {0, 0, 0}}, %% datetime or `unlimited`
{ok, JobName} = ecron:add_with_datetime(JobName, "0 15 14 1 * *", MFA, Start, End).
MFA = {?MODULE, inspect, ["at 14~23:00-15-30-45 on day-of-month 1."]},
Start = {10, 0, 0}, %% time or `unlimited`
End = {22, 15, 0}, %% time or `unlimited`
{ok, JobName} = ecron:add_with_time(JobName, "0 */15 14-23 1 * *", MFA, Start, End).

%% Can only run 100 times at 22:00 on every day-of-week from Monday through Friday.
%% by ecron:add_with_count/3
Expand All @@ -49,7 +49,7 @@ add_limited_run_count_job() ->
add_limited_run_count_job2() ->
MFA = {?MODULE, inspect, ["at minute 0 past hour 0 and 12 on day-of-month 1 in every 2nd month."]},
JobName = limited_run_count_cron_job,
ecron:add_with_count(JobName, "0 22 * * 1-5", MFA, 100).
ecron:add_with_count(ecron_local, JobName, "0 22 * * 1-5", MFA, 100).

%% Delete a specific task
delete_job(JobName) ->
Expand Down
16 changes: 14 additions & 2 deletions examples/titan_erlang/apps/titan/src/titan_sup.erl
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,26 @@ init([]) ->
intensity => 100,
period => 10
},
CrontabName = titan_cron,
Jobs = application:get_env(titan, crontab_jobs, []),
Crontab =
#{
id => CrontabName,
start => {ecron, start_link, [{local, CrontabName}, Jobs]},
restart => permanent,
shutdown => 1000,
type => worker,
modules => [CrontabName]
},
WorkMods = [stateful_cron_by_send_after, stateful_cron_by_send_interval],
ChildSpecs =
[begin
#{id => Mod,
#{
id => Mod,
start => {Mod, start_link, []},
restart => permanent,
shutdown => 1000,
type => worker,
modules => [Mod]
} end || Mod <- WorkMods],
{ok, {SupFlags, ChildSpecs}}.
{ok, {SupFlags, [Crontab|ChildSpecs]}}.
53 changes: 27 additions & 26 deletions examples/titan_erlang/config/sys.config
Original file line number Diff line number Diff line change
@@ -1,35 +1,36 @@
[
{titan, []},
{titan, [
{crontab_jobs, [
%% {JobName, CrontabSpec, {M, F, A}}
%% {JobName, CrontabSpec, {M, F, A}, StartDateTime, EndDateTime}
%% CrontabSpec
%% 1. "Minute Hour DayOfMonth Month DayOfWeek"
%% 2. "Second Minute Hour DayOfMonth Month DayOfWeek"
%% 3. @yearly | @annually | @monthly | @weekly | @daily | @midnight | @hourly | @minutely
%% 4. @every 1h2m3s

%% Standard crontab spec without second (default second is 0 not *).
{crontab_job, "*/15 * * * *", {stateless_cron, inspect, ["Runs on 0, 15, 30, 45 minutes"]}},
%% Extend crontab spec with second.
{extend_crontab_job, "0 0 1-6/2,18 * * *", {stateless_cron, inspect, ["Runs on 1,3,6,18 o'clock"]}},
%% Crontab spec with alphabet.
{alphabet_job, "@hourly", {stateless_cron, inspect, ["Runs every(0-23) o'clock"]}},
%% Fixed interval spec.
{fixed_interval_job, "@every 5m", {stateless_cron, inspect, ["Runs every 5 minutes"]}},
%% Job with startDateTime and EndDateTime. Runs 0-23 o'clock since {11,0,0}.
{limit_datetime_job, "@hourly", {stateless_cron, inspect, ["Runs every(0-23) o'clock"]}, {11, 0, 0}, unlimited},
%% Job with max run count, default is `unlimited`
{max_run_count_job, "@daily", {stateless_cron, inspect, ["Runs daily"]}, unlimited, unlimited, [{max_count, 1000}]},
%% Parallel job, singleton default is true.
{no_singleton_job, "@minutely", {timer, sleep, [61000]}, unlimited, unlimited, [{singleton, false}]}

]}
]},
{ecron, [
{time_zone, local}, %% local or utc
{global_quorum_size, 1},
{global_jobs, [
{global_crontab_job, "*/15 * * * * *", {stateless_cron, inspect, ["Runs on 0, 15, 30, 45 seconds"]}}
]},
{local_jobs, [
%% {JobName, CrontabSpec, {M, F, A}}
%% {JobName, CrontabSpec, {M, F, A}, StartDateTime, EndDateTime}
%% CrontabSpec
%% 1. "Minute Hour DayOfMonth Month DayOfWeek"
%% 2. "Second Minute Hour DayOfMonth Month DayOfWeek"
%% 3. @yearly | @annually | @monthly | @weekly | @daily | @midnight | @hourly | @minutely
%% 4. @every 1h2m3s

%% Standard crontab spec without second (default second is 0 not *).
{crontab_job, "*/15 * * * *", {stateless_cron, inspect, ["Runs on 0, 15, 30, 45 minutes"]}},
%% Extend crontab spec with second.
{extend_crontab_job, "0 0 1-6/2,18 * * *", {stateless_cron, inspect, ["Runs on 1,3,6,18 o'clock"]}},
%% Crontab spec with alphabet.
{alphabet_job, "@hourly", {stateless_cron, inspect, ["Runs every(0-23) o'clock"]}},
%% Fixed interval spec.
{fixed_interval_job, "@every 5m", {stateless_cron, inspect, ["Runs every 5 minutes"]}},
%% Job with startDateTime and EndDateTime. Runs 0-23 o'clock since {{2019,9,26},{0,0,0}}.
{limit_datetime_job, "@hourly", {stateless_cron, inspect, ["Runs every(0-23) o'clock"]}, {{2019, 9, 26}, {0, 0, 0}}, unlimited},
%% Job with max run count, default is `unlimited`
{max_run_count_job, "@daily", {stateless_cron, inspect, ["Runs daily"]}, unlimited, unlimited, [{max_count, 1000}]},
%% Parallel job, singleton default is true.
{no_singleton_job, "@minutely", {timer, sleep, [61000]}, unlimited, unlimited, [{singleton, false}]}

]}
]}
].
7 changes: 5 additions & 2 deletions examples/titan_erlang/rebar.lock
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
{"1.1.0",
{"1.2.0",
[{<<"ecron">>,{pkg,<<"ecron">>,<<"0.5.2">>},0},
{<<"telemetry">>,{pkg,<<"telemetry">>,<<"0.4.0">>},1}]}.
[
{pkg_hash,[
{<<"ecron">>, <<"66E092F1E41C6C52DE7C0C88F023ECC0DBE44FBB614BD9BC8ABA38BA5B6DEFF0">>},
{<<"telemetry">>, <<"8339BEE3FA8B91CB84D14C2935F8ECF399CCD87301AD6DA6B71C09553834B2AB">>}]}
{<<"telemetry">>, <<"8339BEE3FA8B91CB84D14C2935F8ECF399CCD87301AD6DA6B71C09553834B2AB">>}]},
{pkg_hash_ext,[
{<<"ecron">>, <<"6FEB15514E9BD60B7696AABA9C405AEA8F950C8CA1D8E1FD4C702A12073F30C6">>},
{<<"telemetry">>, <<"E9E3CACFD37C1531C0CA70CA7C0C30CE2DBB02998A4F7719DE180FE63F8D41E4">>}]}
].
21 changes: 17 additions & 4 deletions include/ecron.hrl
Original file line number Diff line number Diff line change
@@ -1,13 +1,26 @@
-define(MONITOR_WORKER, ecron_monitor).
-define(Job, ecron_local_jobs).
-define(GlobalJob, ecron_global_jobs).
-define(LocalJob, ecron_local).
-define(GlobalJob, ecron_global).
-define(Ecron, ecron).

-define(MAX_TIMEOUT, 4294967). %% (16#ffffffff div 1000) 49.71 days.
%% (16#ffffffff div 1000) 49.71 days.
-define(MAX_TIMEOUT, 4294967).
-define(Success, [ecron, success]).
-define(Failure, [ecron, failure]).
-define(Activate, [ecron, activate]).
-define(Deactivate, [ecron, deactivate]).
-define(Delete, [ecron, delete]).
-define(GlobalUp, [ecron, global, up]).
-define(GlobalDown, [ecron, global, down]).
-define(GlobalDown, [ecron, global, down]).

-record(job, {
name,
status = activate,
job,
opts = [],
ok = 0,
failed = 0,
link = undefined,
result = [],
run_microsecond = []
}).
7 changes: 7 additions & 0 deletions rebar.config
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,10 @@
{xref_checks,[undefined_function_calls,undefined_functions,locals_not_used,
deprecated_function_calls,
deprecated_functions]}.

{project_plugins, [rebar3_format, erlfmt]}.
{format, [
{files, ["src/*.erl", "include/*.hrl"]},
{formatter, erlfmt_formatter}, %% The erlfmt formatter interface.
{options, #{print_width => 120, ignore_pragma => true}} %% ...or no options at all.
]}.
6 changes: 4 additions & 2 deletions rebar.lock
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
{"1.1.0",
{"1.2.0",
[{<<"telemetry">>,{pkg,<<"telemetry">>,<<"0.4.0">>},0}]}.
[
{pkg_hash,[
{<<"telemetry">>, <<"8339BEE3FA8B91CB84D14C2935F8ECF399CCD87301AD6DA6B71C09553834B2AB">>}]}
{<<"telemetry">>, <<"8339BEE3FA8B91CB84D14C2935F8ECF399CCD87301AD6DA6B71C09553834B2AB">>}]},
{pkg_hash_ext,[
{<<"telemetry">>, <<"E9E3CACFD37C1531C0CA70CA7C0C30CE2DBB02998A4F7719DE180FE63F8D41E4">>}]}
].
12 changes: 6 additions & 6 deletions src/ecron.app.src
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{application, ecron,
[{description, "cron-like/crontab job scheduling library"},
{vsn, "0.5.3"},
{registered, [ecron_sup, ecron, ecron_monitor]},
{vsn, "0.6.0"},
{registered, [ecron_sup, ecron_local, ecron_monitor]},
{mod, {ecron_app, []}},
{applications, [kernel, stdlib, telemetry]},
{env, [
Expand All @@ -10,7 +10,7 @@
{global_quorum_size, 1}, %% A majority of the nodes must connect.
{local_jobs, [
%% {JobName, CrontabSpec, {M, F, A}}
%% {JobName, CrontabSpec, {M, F, A}, StartDateTime, EndDateTime}
%% {JobName, CrontabSpec, {M, F, A}, StartTime, EndTime}
%% CrontabSpec
%% 1. "Minute Hour DayOfMonth Month DayOfWeek"
%% 2. "Second Minute Hour DayOfMonth Month DayOfWeek"
Expand All @@ -20,11 +20,11 @@
%% {extend_crontab_job, "0 0 1-6/2,18 * * *", {io, format, ["Runs on 1,3,6,18 o'clock:~n"]}},
%% {alphabet_job, "@hourly", {io, format, ["Runs every(0-23) o'clock~n"]}},
%% {fixed_interval_job, "@every 30m", {io, format, ["Runs every 30 minutes"]}},
%% Runs 0-23 o'clock since {{2019,9,26},{0,0,0}}.
%% {limit_datetime_job, "@hourly", {io, format, ["Runs every(0-23) o'clock~n"]}, {{2019,9,26},{0,0,0}}, unlimited}
%% Runs every 15 minutes between {8,20,0} and {23, 59, 59}.
%% {limit_time_job, "*/15 * * * *", {io, format, ["Runs 0, 15, 30, 45 minutes after 8:20am~n"]}, {8,20,0}, unlimited}
]},
{global_jobs, [
%% {global_job, "*/10 * * * * *", {io, format, ["Runs on 0, 15, 30, 45 seconds~n"]}}
%% {global_job, "*/15 * * * * *", {io, format, ["Runs on 0, 15, 30, 45 seconds~n"]}}
]}
]},
{modules, []},
Expand Down
Loading

0 comments on commit b3c6dce

Please sign in to comment.