Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I schedule code to run every few hours in Elixir or Phoenix framework?

There is a simple alternative that does not require any external dependencies:

defmodule MyApp.Periodically do
  use GenServer

  def start_link(_opts) do
    GenServer.start_link(__MODULE__, %{})
  end

  def init(state) do
    schedule_work() # Schedule work to be performed at some point
    {:ok, state}
  end

  def handle_info(:work, state) do
    # Do the work you desire here
    schedule_work() # Reschedule once more
    {:noreply, state}
  end

  defp schedule_work() do
    Process.send_after(self(), :work, 2 * 60 * 60 * 1000) # In 2 hours
  end
end

Now in your supervision tree:

children = [
  MyApp.Periodically
]

Supervisor.start_link(children, strategy: :one_for_one)

Quantum lets you create, find and delete jobs at runtime.

Furthermore, you can pass arguments to the task function when creating a cronjob, and even modify the timezone if you're not happy with UTC.

If your app is running as multiple isolated instances (e.g. Heroku), there are job processors backed by PostgreSQL or Redis, that also support task scheduling:

Oban: https://github.com/sorentwo/oban

Exq: https://github.com/akira/exq

Toniq: https://github.com/joakimk/toniq

Verk: https://github.com/edgurgel/verk


You can use erlcron for that. You use it like

job = {{:weekly, :thu, {2, :am}},
  {:io, :fwrite, ["It's 2 Thursday morning~n"]}}

:erlcron.cron(job)

A job is a 2-element tuple. The first element is a tuple that represents the schedule for the job and the second element is the function or an MFA(Module, Function, Arity). In the above example, we run :io.fwrite("It's 2 Thursday morning") every 2am of Thursday.

Hope that helps!


I used Quantum library Quantum- Elixir.
Follow below instructions.

#your_app/mix.exs
defp deps do
  [{:quantum, ">= 1.9.1"},  
  #rest code
end



#your_app/mix.exs
def application do
  [mod: {AppName, []},
   applications: [:quantum,
   #rest code         
 ]]
end

#your_app/config/dev.exs
config :quantum, :your_app, cron: [
  # Every minute
  "* * * * *": fn -> IO.puts("Hello QUANTUM!") end
]

All set. Start the server by running below command.

iex -S mix phoenix.server 

I find :timer.send_interval/2 slightly more ergonomic to use with a GenServer than Process.send_after/4 (used in the accepted answer).

Instead of having to reschedule your notification each time you handle it, :timer.send_interval/2 sets up an interval on which you receive a message endlessly—no need to keep calling schedule_work() like the accepted answer uses.

defmodule CountingServer do
  use GenServer

  def init(_) do
    :timer.send_interval(1000, :update)
    {:ok, 1}
  end

  def handle_info(:update, count) do
    IO.puts(count)
    {:noreply, count + 1}
  end
end

Every 1000 ms (i.e., once a second), IntervalServer.handle_info/2 will be called, print the current count, and update the GenServer's state (count + 1), giving you output like:

1
2
3
4
[etc.]

Besides to use Process.send_after, you can also use :timer.apply_interval.