0

I'm developing an app in my desktop computer (Mac OS) for which I created some cron tasks that run every 5 minutes. The code is the following (taken from here):

defmodule MyApp.CronJobs do
  use GenServer

  @shops ["billa","kaufland","lidl"] 

  def start_link 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
    Enum.each(@shops, &monitor_prices/1)
    schedule_work() # Reschedule once more
    {:noreply, state}
  end

  defp monitor_price(shop)
    Mix.Task.run "monitor.#{shop}.all_prices"
  end

  defp schedule_work() do
    Process.send_after(self(), :work, 5 * 60 * 1000)
  end
end

On Supervision tree:

  ...
  children = [
    supervisor(MyApp.CronJobs, [])
    ...
  ]
  opts = [ strategy: :one_for_one, name: MyApp.Supervisor]
  Supervisor.start_link(children, opts)

The problem is this runs with the server, so whenever the computer goes on Sleep mode it stops running.

Is there a way to have the processes running on the background permanently without having the computer all the time in Full Power mode? Even better, Is there a way to have mix Tasks triggered every 5 minutes without running the server?

ntonnelier
  • 1,539
  • 3
  • 23
  • 49
  • 1
    Sleeping is somewhat analogous to turning your computer off, and there's no way to run any process in sleep mode, since all the processes are paused, so if you want to keep tasks running you have to disable sleep mode and keep it always turned on. Or deploy your app somewhere. Why do you need all those tasks running in dev mode? BTW you're not using cron here at all, it's BEAM's internal process scheduling – Bogdan Agafonov Sep 19 '18 at 18:46
  • i understand this is not really cron jobs, but they manage the same @BogdanAgafonov . Ideally I would like to trigger mix tasks at a certain interval without needing to run a server, but I don't know how to achieve that from within the elixir app. – ntonnelier Sep 19 '18 at 21:01
  • You want to run something as a "daemon". Easiest way is probably to convert your code to a mix task and use CRON, but you can also look at distillery releases + sysctl or other daemonizer. You can also just run it in the background using sysctl and iex directly. – jonzlin95 Sep 19 '18 at 21:53

1 Answers1

0

You can program OSX with a scheduled wakeup and sleep so this could solve your sleeping issue. You can also coordinate a "real" cron job to run either a script in the same window.

The problem with mix tasks is that they usually run from a project's root folder since they need the context of the project to run. This is not really a "production" solution. You install an archive that will run from any directory, but there is a better way.

Take a look escripts. You build an escript for a mix project and install it on you system. You can then run the escript from your scheduled cron job.

I doubt you will need a GenServer in your solution since your example above is not using any persistent state. If you need concurrency, you can simply spawn some processes or use Task to run some concurrent code.

Depending on the complexity of your full solution, you may want to look at Distillery to package a release for your project, but this may be overkill.

Steve Pallen
  • 4,417
  • 16
  • 33