Skip to content

Commit

Permalink
Example (#4)
Browse files Browse the repository at this point in the history
* export clear/0

* erlang example release

* elixir example

* update link

* update 0.3.0
  • Loading branch information
zhongwencool authored Oct 17, 2019
1 parent be4c5d0 commit baec9a4
Show file tree
Hide file tree
Showing 32 changed files with 781 additions and 24 deletions.
6 changes: 4 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ It offers:
* Use gen_server timeout(`receive after`) at any given time (rather than reevaluating upcoming jobs every second/minute).
* Minimal overhead. ecron aims to keep its code base small.

You can find more [Erlang Specific Usage](https://github.com/zhongwencool/ecron/blob/master/examples/titan_erlang) and [Elixir Specific Usage]((https://github.com/zhongwencool/ecron/blob/master/examples/titan_elixir)).

## Basic Usage

```erlang
Expand All @@ -46,8 +48,8 @@ It offers:
{limit_datetime_job, "@hourly", {io, format, ["Runs every(0-23) o'clock~n"]}, {{2019,9,26},{0,0,0}}, unlimited},
%% parallel job
{no_singleton_job, "@minutely", {timer, sleep, [61000]}, unlimited, unlimited, [{singleton, false}]}
]}
]
]}}
].
```

* When `time_zone` is `local`, current datetime is [calendar:local_time()](http://erlang.org/doc/man/calendar.html#local_time-0).
Expand Down
5 changes: 5 additions & 0 deletions examples/titan_elixir/.formatter.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Used by "mix format"
[
inputs: ["mix.exs", "config/*.exs"],
subdirectories: ["apps/*"]
]
6 changes: 6 additions & 0 deletions examples/titan_elixir/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
/_build
/deps
/docs
/doc
erl_crash.dump
*.ez
4 changes: 4 additions & 0 deletions examples/titan_elixir/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# Titan

**TODO: Add description**

4 changes: 4 additions & 0 deletions examples/titan_elixir/apps/titan/.formatter.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# Used by "mix format"
[
inputs: ["{mix,.formatter}.exs", "{config,lib,test}/**/*.{ex,exs}"]
]
6 changes: 6 additions & 0 deletions examples/titan_elixir/apps/titan/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
/_build
/deps
/docs
/doc
erl_crash.dump
*.ez
21 changes: 21 additions & 0 deletions examples/titan_elixir/apps/titan/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Titan

**TODO: Add description**

## Installation

If [available in Hex](https://hex.pm/docs/publish), the package can be installed
by adding `titan` to your list of dependencies in `mix.exs`:

```elixir
def deps do
[
{:titan, "~> 0.1.0"}
]
end
```

Documentation can be generated with [ExDoc](https://github.com/elixir-lang/ex_doc)
and published on [HexDocs](https://hexdocs.pm). Once published, the docs can
be found at [https://hexdocs.pm/titan](https://hexdocs.pm/titan).

18 changes: 18 additions & 0 deletions examples/titan_elixir/apps/titan/lib/titan.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
defmodule Titan do
@moduledoc """
Documentation for Titan.
"""

@doc """
Hello world.
## Examples
iex> Titan.hello()
:world
"""
def hello do
:world
end
end
21 changes: 21 additions & 0 deletions examples/titan_elixir/apps/titan/lib/titan/application.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
defmodule Titan.Application do
# See https://hexdocs.pm/elixir/Application.html
# for more information on OTP Applications
@moduledoc false

use Application

def start(_type, _args) do
children = [
# Starts a worker by calling: Titan.Worker.start_link(arg)
# {Titan.Worker, arg}
{StatefulCron.SendInterval, []},
{StatefulCron.SendAfter, []},
]

# See https://hexdocs.pm/elixir/Supervisor.html
# for other strategies and supported options
opts = [strategy: :one_for_one, name: Titan.Supervisor]
Supervisor.start_link(children, opts)
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
defmodule StatefulCron.SendAfter do
@moduledoc false

use GenServer

def start_link(state) do
GenServer.start_link(__MODULE__, state, name: __MODULE__)
end

def cancel_weekend_staff() do
GenServer.call(__MODULE__, :cancel_weekend_staff)
end

def init([]) do
{:ok, ref} = send_after_weekend_msg()
{:ok, %{timer_ref: ref}}
end

def handle_call(:cancel_weekend_staff, _from, state = %{timer_ref: :undefined}) do
{:reply, :ok, state}
end
def handle_call(:cancel_weekend_staff, _from, state = %{timer_ref: ref}) do
Process.cancel_timer(ref)
{:reply, :ok, state}
end

def handle_call(_msg, _from, state) do
{:reply, :ok, state}
end

def handle_cast(_msg, state) do
{:noreply, state}
end

def handle_info(:weekend_staff, state) do
do_weekend_staff()
{:ok, ref} = send_after_weekend_msg()
{:noreply, %{state | timer_ref: ref}}
end

###===================================================================
### Internal functions
###===================================================================

#The timer will be automatically canceled
#if the given dest is a PID which is not alive or when the given PID no-exits.
# behaviour as Process.send_after/3
def send_after_weekend_msg() do
:ecron.send_after("0 0 20 * * 0,6", self(), :weekend_staff)
end

def do_weekend_staff() do
now = :calendar.system_time_to_rfc3339(System.system_time(:second))
IO.inspect("do weekday staff at #{now}")
end

end
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
defmodule StatefulCron.SendInterval do
@moduledoc false

use GenServer
@monthly_job_name :monthly_staff_job

def start_link(state), do: GenServer.start_link(__MODULE__, state, name: __MODULE__)

def cancel_workday_staff(), do: GenServer.call(__MODULE__, :cancel_workday_staff)

def cancel_monthly_staff(), do: :ecron.delete(@monthly_job_name)

def init([]) do
## If this process die, the crontab will auto delete.
## It's not necessary to delete job when terminate.
{:ok, job_ref} = :ecron.send_interval("0 0 8 * * 1-5", self(), :workday_staff)
start_time = {{2020, 1, 1}, {0, 0, 0}}
end_time = {{2022, 1, 1}, {0, 0, 1}}
:ecron.send_interval(@monthly_job_name, "@monthly", self(), :monthly_staff, start_time, end_time, [])
{:ok, %{workday_job: job_ref}}
end

def handle_call(:cancel_workday_staff, _from, state = %{workday_job: job_ref}) do
:ecron.delete(job_ref)
{:reply, :ok, %{state | workday_job: :undefined}}
end
def handle_call(_msg, _from, state) do
{:reply, :ok, state}
end

def handle_cast(_msg, state) do
{:noreply, state}
end

def handle_info(:workday_staff, state) do
do_send_workday_staff(state)
{:noreply, state}
end
def handle_info(:monthly_staff, state) do
do_send_monthly_staff(state)
{:noreply, state}
end
def handle_info(_msg, state) do
{:noreply, state}
end

## ===================================================================
## Internal functions
## ===================================================================
def do_send_workday_staff(_state) do
now = :calendar.system_time_to_rfc3339(System.system_time(:second))
IO.inspect("do workday staff at #{now}")
end

def do_send_monthly_staff(_State) do
now = :calendar.system_time_to_rfc3339(System.system_time(:second))
IO.inspect("Do monthly staff at #{now}}")
end

end
92 changes: 92 additions & 0 deletions examples/titan_elixir/apps/titan/lib/titan/stateless_cron.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
defmodule StatelessCron do
@moduledoc false

## Add job run at 04:00 everyday.
## by ecron:add/3
def add_every_4am_job() do
job_name = :every_4am_job
mfa = {__MODULE__, :insepct, ["at 04:00 everyday."]}
{:ok, ^job_name} = :ecron.add(job_name, "0 4 * * *", mfa)
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
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)
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
def add_limited_start_end_datetime_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)
end

## Can only run 100 times at 22:00 on every day-of-week from Monday through Friday.
## by ecron:add_with_count / 3
def add_limited_run_count_job() do
mfa = {__MODULE__, :inspect, ["at 22:00 on every day-of-week from Monday through Friday."]}
:ecron.add_with_count("0 22 * * 1-5", mfa, 100)
end

## Can only run 100 times at minute 0 past hour 0 and 12 on day-of-month 1 in every 2nd month.
## by ecron:add_with_count/4
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)
end

## Delete a specific task
def delete_job(job_name) do
:ok = :ecron.delete(job_name)
end

## MFA
def inspect(format) do
now = System.system_time(:second) |> :calendar.system_time_to_rfc3339()
IO.inspect("#{now} : #{format}")
end

## %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
## Debug Functions Begin
## %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
##
## Pause job temporary
def deactivate_job(job_name) do
:ecron.deactivate(job_name)
end

## Rerun job.
def activate_job(job_name) do
:ecron.activate(job_name)
end

## Inspect specific statistic
def job_stats(job_name) do
:ecron.statistic(job_name)
end

## Inspect all statistic
def all_job_stats() do
:ecron.statistic()
end

## Predict latest N datetime.
def predict_datetime_by_spec(spec, n) do
:ecron.parse_spec(spec, n)
end

## %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
## Debug Functions End
## %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

end
35 changes: 35 additions & 0 deletions examples/titan_elixir/apps/titan/mix.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
defmodule Titan.MixProject do
use Mix.Project

def project do
[
app: :titan,
version: "0.1.0",
build_path: "../../_build",
config_path: "../../config/config.exs",
deps_path: "../../deps",
lockfile: "../../mix.lock",
elixir: "~> 1.9",
start_permanent: Mix.env() == :prod,
deps: deps()
]
end

# Run "mix help compile.app" to learn about applications.
def application do
[
extra_applications: [:logger],
mod: {Titan.Application, []}
]
end

# Run "mix help deps" to learn about dependencies.
defp deps do
[
# {:dep_from_hexpm, "~> 0.3.0"},
# {:dep_from_git, git: "https://github.com/elixir-lang/my_dep.git", tag: "0.1.0"},
# {:sibling_app_in_umbrella, in_umbrella: true}
{:ecron, ">= 0.3.0"}
]
end
end
Loading

0 comments on commit baec9a4

Please sign in to comment.