Current section

Files

Jump to
quantum lib quantum.ex
Raw

lib/quantum.ex

defmodule Quantum do
use GenServer
@typedoc "A function/0 to be called when cron expression matches"
@type fun0 :: (() -> Type)
@typedoc "A job is defined by a cron expression and a function/0"
@type job :: {String.t | Atom, fun0}
@doc "Adds a new job"
@spec add_job(String.t, fun0) :: :ok
def add_job(spec, job) do
GenServer.call(__MODULE__, {:add_job, convert(spec), job})
end
@doc "Returns the list of currently defined jobs"
@spec jobs :: [job]
def jobs do
GenServer.call(__MODULE__, :jobs)
end
def init(_) do
tick
jobs = Application.get_env(:quantum, :cron, [])
|> Enum.map(&convert/1)
|> Enum.filter(&reboot/1)
{:ok, %{jobs: jobs, d: nil, h: nil, m: nil, w: nil}}
end
def handle_call({:add_job, spec, job}, _from, state) do
{:reply, :ok, %{state | jobs: [{spec, job} | state.jobs]}}
end
def handle_call(:jobs, _from, state) do
{:reply, state.jobs, state}
end
def handle_info(:tick, state) do
{d, h, m} = tick
if state.d != d, do: state = %{state | d: d, w: rem(:calendar.day_of_the_week(d), 7)}
state = %{state | h: h, m: m}
Enum.each(state.jobs, fn({e, fun}) -> execute(e, fun, state) end)
{:noreply, state}
end
def handle_info(_, state), do: {:noreply, state}
defp convert({e, fun}), do: {convert(e), fun}
defp convert(e) when e |> is_atom, do: convert e |> Atom.to_string
defp convert(e), do: e |> String.downcase |> Quantum.Translator.translate
defp execute(e, fun, state) do
Task.start(Quantum.Executor, :execute, [e, fun, state])
end
defp reboot({"@reboot", fun}) do
Task.start(fun)
false
end
defp reboot(_), do: true
defp tick do
{d, {h, m, s}} = :calendar.now_to_universal_time(:os.timestamp)
Process.send_after(self, :tick, (60 - s) * 1000)
{d, h, m}
end
end