Wie kann ich festlegen, dass Code alle paar Stunden im Elixir- oder Phoenix-Framework ausgeführt wird?

193

Nehmen wir also an, ich möchte alle 4 Stunden ein paar E-Mails senden oder eine Sitemap oder was auch immer neu erstellen. Wie würde ich das in Phoenix oder nur mit Elixir machen?

NoDisplayName
quelle

Antworten:

385

Es gibt eine einfache Alternative, die keine externen Abhängigkeiten erfordert:

defmodule MyApp.Periodically do
  use GenServer

  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
    # 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

Jetzt in Ihrem Überwachungsbaum:

worker(MyApp.Periodically, [])
José Valim
quelle
166
Es ist unmöglich, diese Sprache nicht zu lieben :)
NoDisplayName
3
Wo soll ich diese Datei ablegen? Unter lib / Verzeichnis des Phoenix-Projekts? Wohin geht der Test, um / regelmäßig / * zu testen?
EugZol
9
In lib, weil es ein lang laufender Prozess ist. Sie können den Test so ausführen, wie es sinnvoll ist, z. B. "test / my_app / periodically_test.exs".
José Valim
2
Gibt es einen bestimmten Grund, nicht Process.send_afterin eine eigene Funktion zu wechseln, damit die Funktion von beiden initund aufgerufen werden kann handle_info?
Ryan Bigg
24
@CodyPoll :timer.send_intervalist in Ordnung, aber denken Sie daran, dass die Intervalle konstant bleiben. Stellen Sie sich vor, Sie möchten jede Minute etwas tun, und in Zukunft dauert die Arbeit selbst mehr als eine Minute. In solchen Fällen würden Sie die ganze Zeit arbeiten und Ihre Nachrichtenwarteschlange würde unbegrenzt wachsen. Die obige Lösung wartet immer die angegebene Zeit, nachdem die Arbeit erledigt ist.
José Valim
32

Mit Quantum können Sie Jobs zur Laufzeit erstellen, suchen und löschen.

Darüber hinaus können Sie beim Erstellen eines Cronjobs Argumente an die Taskfunktion übergeben und sogar die Zeitzone ändern, wenn Sie mit UTC nicht zufrieden sind.

Wenn Ihre App als mehrere isolierte Instanzen ausgeführt wird (z. B. Heroku), gibt es Jobprozessoren, die von PostgreSQL oder Redis unterstützt werden und die auch die Aufgabenplanung unterstützen:

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

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

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

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

Svilen
quelle
1
Ich denke, es wird ein Overkill für viele einfache Aufgaben sein, die es nicht erfordern, aber ich danke Ihnen trotzdem für die Antwort.
NoDisplayName
Es war hilfreich für mich, eine Liste der verfügbaren Bibliotheken zu haben.
Sheldonkreger
24

Sie können dafür Erlcron verwenden . Du benutzt es gerne

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

:erlcron.cron(job)

A jobist ein 2-Element-Tupel. Das erste Element ist ein Tupel, das den Zeitplan für den Job darstellt, und das zweite Element ist die Funktion oder ein MFA (Modul, Funktion, Arität). Im obigen Beispiel laufen wir :io.fwrite("It's 2 Thursday morning")jeden Donnerstag um 2 Uhr morgens.

Hoffentlich hilft das!

Gjaldon
quelle
Ja, es ist besser als nichts, danke. Ich werde die Frage für eine Weile unbeantwortet lassen, vielleicht gibt es andere Vorschläge
NoDisplayName
4
Bitte! Es gibt auch github.com/c-rack/quantum-elixir, das eine
Elixierbibliothek
6

Ich habe die Quantenbibliothek Quantum-Elixir verwendet .
Befolgen Sie die nachstehenden Anweisungen.

#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
]

Alles bereit. Starten Sie den Server, indem Sie den folgenden Befehl ausführen.

iex -S mix phoenix.server 
Shashidhar Mayannavar
quelle
Dies ist wie Cronjobs
DarckBlezzer
1

Ich finde es :timer.send_interval/2etwas ergonomischer, mit einem zu arbeiten GenServerals Process.send_after/4(in der akzeptierten Antwort verwendet ).

Anstatt Ihre Benachrichtigung jedes Mal neu planen zu müssen, legen Sie :timer.send_interval/2ein Intervall fest, in dem Sie endlos eine Nachricht erhalten - Sie müssen nicht weiter anrufen, schedule_work()wie es die akzeptierte Antwort verwendet.

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

Alle 1000 ms (dh einmal pro Sekunde) IntervalServer.handle_info/2wird aufgerufen, der aktuelle countWert gedruckt und der Status des GenServers aktualisiert ( count + 1), sodass Sie folgende Ausgaben erhalten:

1
2
3
4
[etc.]
s3cur3
quelle
0

Quantum ist großartig, wir verwenden es bei der Arbeit als Cron-Ersatz mit einem Phoenix-Frontend und wir fügen auch Jobs in Echtzeit hinzu, was sehr ordentlich ist.

Danke
quelle