Kodu Elixir veya Phoenix çerçevesinde birkaç saatte bir çalışacak şekilde nasıl zamanlayabilirim?


194

Diyelim ki bir grup e-posta göndermek veya site haritasını yeniden oluşturmak istiyorum ya da her 4 saatte bir, bunu Phoenix'te veya sadece Elixir ile nasıl yapabilirim?

Yanıtlar:


390

Herhangi bir dış bağımlılık gerektirmeyen basit bir alternatif var:

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

Şimdi denetim ağacında:

worker(MyApp.Periodically, [])

170
Bu dili
sevmemek

3
Bu dosyayı nereye koymalıyım? Phoenix projesinin lib / dizini altında mı? Test / periyodik olarak / * testine nereye gidiyor?
EugZol

9
Lib'de uzun süren bir süreç olduğu için. Testi "mantıklı / uygulamam / periyodik_test.exs" gibi mantıklı bir şekilde yapabilirsiniz.
José Valim

2
Her Process.send_afteriki işlevden de çağrılabilmesi için kendi işlevine geçmemek için herhangi bir özel neden initve handle_info?
Ryan Bigg

24
@CodyPoll :timer.send_intervaliyidir, ancak aralıkların sabit olacağını unutmayın. Her dakika bir şeyler yapmak istediğinizi düşünün ve gelecekte işin kendisi bir dakikadan fazla sürüyor. Bu gibi durumlarda her zaman çalışırsınız ve mesaj kuyruğunuz sınırsız büyür. Yukarıdaki çözüm her zaman iş bittikten sonra belirtilen süreyi bekleyecektir .
José Valim

33

Quantum , çalışma zamanında iş oluşturmanıza, bulmanıza ve silmenize olanak tanır.

Ayrıca, bir cronjob oluştururken görev işlevine bağımsız değişkenler iletebilir ve hatta UTC'den memnun değilseniz saat dilimini değiştirebilirsiniz.

Uygulamanız birden çok yalıtılmış örnek olarak çalışıyorsa (örn. Heroku), görev zamanlamasını da destekleyen PostgreSQL veya Redis tarafından desteklenen iş işlemcileri vardır:

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

Örnek: https://github.com/akira/exq

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

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


1
Sanırım gerektirmeyen birçok basit görev için aşırıya kaçacak ama yine de cevap için teşekkür ederim.
NoDisplayName

Kütüphanelerin bir listesini bulundurmak benim için yararlı oldu.
sheldonkreger

25

Bunun için erlcron kullanabilirsiniz . Gibi kullanıyorsun

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

:erlcron.cron(job)

A job, 2 elemanlı bir demettir. İlk öğe, işin zamanlamasını temsil eden bir demettir ve ikinci öğe işlev veya bir MFA'dır (Modül, İşlev, Arity). Yukarıdaki örnekte, :io.fwrite("It's 2 Thursday morning")Perşembe gününün her 2 am'ını çalıştırıyoruz .

Umarım yardımcı olur!


Evet, hiç yoktan iyidir, teşekkür ederim. Soruyu bir süre cevapsız bırakacağım, belki başka öneriler olacak
NoDisplayName

4
Rica ederim! Orada da github.com/c-rack/quantum-elixir dilerseniz bir iksir lib olan
Gjaldon

6

Quantum kütüphanesi Quantum- Elixir kullandım .
Aşağıdaki talimatları izleyin.

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

Her şey hazır. Aşağıdaki komutu çalıştırarak sunucuyu başlatın.

iex -S mix phoenix.server 

Bu cronjobs gibi
DarckBlezzer

1

Ben bulmak :timer.send_interval/2bir ile kullanmak biraz daha ergonomik GenServerdaha Process.send_after/4(kullanılan kabul edilen cevap ).

Bildiriminizi her kullandığınızda yeniden planlamak zorunda kalmak yerine, :timer.send_interval/2sonsuz bir ileti aldığınız bir aralık belirler schedule_work(); kabul edilen yanıtın kullandığı gibi aramaya devam etmenize gerek yoktur .

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

Her 1000 ms'de (yani saniyede bir kez) IntervalServer.handle_info/2çağrılacak, akımı yazdıracak countve GenServer'ın durumunu ( count + 1) güncelleyeceksiniz.

1
2
3
4
[etc.]


Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.