Packages
tarearbol
0.4.3
1.12.0
1.11.2
1.11.1
1.11.0
1.10.4
1.10.3
1.10.2
1.10.0
1.9.102
1.9.101
1.9.100
1.9.99
1.9.11
1.9.10
1.9.9
1.9.8
1.9.7
1.9.6
1.9.5
1.9.4
1.9.3
1.9.2
1.9.1
1.9.0
1.8.2
1.8.1
1.8.0
1.7.0
1.6.8
1.6.7
1.6.6
1.6.5
1.6.4
1.6.3
1.6.2
1.6.1
1.6.0
1.5.0
1.4.4
1.4.3
1.4.2
1.4.1
1.4.0
1.3.0
1.2.1
1.2.0
1.1.2
1.1.1
1.1.0
1.0.4
1.0.3
1.0.2
1.0.0
0.99.11
0.99.10
0.99.9
0.99.8
0.99.7
0.99.6
0.99.4
0.99.3
0.99.2
0.99.1
0.99.0
0.14.1
0.14.0
0.13.3
0.13.2
0.13.1
0.13.0
0.12.1
0.12.0
0.11.0
0.10.0
0.9.6
0.9.5
0.9.3
0.9.2
0.9.1
0.9.0
0.8.2
0.8.1
0.8.0
0.7.0
0.6.0
0.5.1
0.5.0
0.4.3
0.4.2
0.4.1
0.4.0
0.3.3
0.3.2
0.3.1
0.3.0
0.2.2
0.2.1
0.2.0
0.1.0
The supervised tree of tasks, simplifying the process of handling: - recurrent tasks - retried tasks - long tasks - etc
Current section
Files
Jump to
Current section
Files
lib/tarearbol/errand.ex
defmodule Tarearbol.Errand do
@moduledoc false
require Logger
@default_opts [
repeatedly: false
]
@msecs_per_day 1_000 * 60 * 60 * 24
@doc """
Runs the task either once at the specified `%DateTime{}` or repeatedly
at the specified `%Time{}`.
"""
@spec run_in(Function.t | {Module.t, Atom.t, List.t},
Tarearbol.Utils.interval, Keyword.t) :: Task.t
def run_in(job, interval, opts \\ opts()) do
Tarearbol.Application.task!(fn ->
waiting_time = Tarearbol.Utils.interval(interval, value: 0)
Process.put(:job, {job, opts, Tarearbol.Utils.add_interval(interval)})
Process.sleep(waiting_time)
result = Tarearbol.Job.ensure(job, opts)
Process.delete(:job)
cond do
opts[:sidekiq] -> run_in(job, sidekiq_interval(waiting_time), opts)
opts[:next_run] -> run_at(job, opts[:next_run], opts)
opts[:repeatedly] -> run_in(job, interval, opts)
true -> result
end
end)
end
@doc """
Runs the task either once at the specified `%DateTime{}` or repeatedly
at the specified `%Time{}`.
"""
@spec run_at(Function.t | {Module.t, Atom.t, List.t},
DateTime.t | Time.t | String.t, Keyword.t) :: Task.t
def run_at(job, at, opts \\ opts())
def run_at(job, %DateTime{} = at, opts) do
interval = DateTime.diff(at, DateTime.utc_now, :millisecond)
run_in(job, interval, run_in_opts(opts))
end
def run_at(job, %Time{} = at, opts) do
next =
case Time.diff(at, Time.utc_now, :millisecond) do
msec when msec <= 0 -> msec + @msecs_per_day # tomorrow at that time
msec -> msec
end
opts = opts
|> Keyword.put_new(:next_run, at)
|> run_in_opts()
run_in(job, next, opts)
end
def run_at(job, at, opts) when is_binary(at),
do: run_at(job, DateTime.from_iso8601(at), opts)
@doc "Spawns the task by calling `run_in` with a zero interval"
@spec spawn(Function.t | {Module.t, Atom.t, List.t}, Keyword.t) :: Task.t
def spawn(job, opts \\ opts()), do: run_in(job, :none, opts)
##############################################################################
@spec opts() :: Keyword.t
defp opts, do: Application.get_env(:tarearbol, :errand_options, @default_opts)
@spec run_in_opts(Keyword.t) :: Keyword.t
defp run_in_opts(opts), do: Keyword.delete(opts, :repeatedly)
@mike_perham_const 1.15647559215 # to perform 25 times in 21 day
@spec sidekiq_interval(Integer.t) :: Integer.t
defp sidekiq_interval(interval),
do: @mike_perham_const * interval * :math.atan(:math.log(interval))
end