Wait, Bang vs. Bang, Wait: Subtleties in Elixir Cron Scripts

TJ Cron is what you get when your name closely resembles a command line utility
defmodule Cronlike do  use GenServer  @allowed_units [:second, :minute, :hour, :day]  def start_link(state) do
GenServer.start_link(__MODULE__, state)
end
@impl true
def init(%{interval: interval, unit: unit} = state) when is_integer(interval) and interval > 0 and unit in @allowed_units do
# wait, bang:
Process.send_after(self(), :tick, to_ms(interval, unit))
# bang, wait:
# send(self(), :tick)
{:ok, state}
end
@impl true
def handle_info(:tick, %{interval: interval, unit: unit, mod: mod,
fun: fun, args: args} = state) do
# Do Something
apply(mod, fun, args)
Process.send_after(self(), :tick, to_ms(interval, unit)) {:noreply, state}
end
defp to_ms(interval, :second), do: interval * 1000
defp to_ms(interval, :minute), do: to_ms(interval, :second) * 60
defp to_ms(interval, :hour), do: to_ms(interval, :minute) * 60
defp to_ms(interval, :day), do: to_ms(interval, :hour) * 24
end
def start(_type, _args) do  children = [
Supervisor.child_spec(
{Cronlike, %{interval: 1, unit: :second, mod: IO, fun: :puts, args: ["Hi"]}}, id: :thing1),
Supervisor.child_spec(
{Cronlike, %{interval: 2, unit: :second, mod: IO, fun: :puts, args: ["Bye"]}}, id: :thing2)
]
Supervisor.start_link(children, [strategy: :one_for_one, name: MyApp.Supervisor])end
  1. We are using a module attribute @allowed_units to store “constant”-like values in a conspicuous place at the top of our module.
  2. Our function relies on guard clauses to restrict the input.
  3. We are taking advantage of pattern matching when defining multiple function clauses to do our conversion to milliseconds via our to_ms/2 function.
  4. We can spin up multiple instances (am I allowed to use that word in reference to functional programming?) of our Cronlike module by giving each one a unique :id when the app is started.
  5. This module can execute any function by defining its module (via :mod ), function (:fun), and arguments (:args) as arguments to apply/3

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store