¿Cómo puedo programar el código para que se ejecute cada pocas horas en el marco Elixir o Phoenix?

194

Entonces, digamos que quiero enviar un montón de correos electrónicos o recrear el mapa del sitio o lo que sea cada 4 horas, ¿cómo haría eso en Phoenix o simplemente con Elixir?

NoDisplayName
fuente

Respuestas:

387

Existe una alternativa simple que no requiere dependencias externas:

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

Ahora en su árbol de supervisión:

worker(MyApp.Periodically, [])
José Valim
fuente
168
Es imposible no amar este idioma :)
NoDisplayName
3
¿Dónde debo poner este archivo? ¿Bajo lib / directorio del proyecto Phoenix? ¿A dónde va la prueba, para probar / periódicamente / *?
EugZol
9
En lib porque es un proceso de larga duración. Puede poner la prueba lo que tenga sentido, tal vez "test / my_app / periodically_test.exs".
José Valim
2
¿Alguna razón en particular para no pasar Process.send_aftera su propia función para que la función pueda llamarse desde ambos inity handle_info?
Ryan Bigg el
24
@CodyPoll :timer.send_intervalestá bien, pero tenga en cuenta que los intervalos serán constantes. Imagine que quiere hacer algo cada minuto y, en el futuro, el trabajo en sí mismo lleva más de un minuto. En tales casos, estaría trabajando todo el tiempo y su cola de mensajes crecería sin límites. La solución anterior siempre esperará el período dado después de que se realice el trabajo.
José Valim
32

Quantum le permite crear, encontrar y eliminar trabajos en tiempo de ejecución.

Además, puede pasar argumentos a la función de tarea al crear un cronjob e incluso modificar la zona horaria si no está satisfecho con UTC.

Si su aplicación se ejecuta como varias instancias aisladas (por ejemplo, Heroku), hay procesadores de trabajo respaldados por PostgreSQL o Redis, que también admiten la programación de tareas:

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

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

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

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

Svilen
fuente
1
Creo que será una exageración para muchas tareas simples que no lo requieren, pero gracias por la respuesta de todos modos.
NoDisplayName
Tener una lista de bibliotecas disponibles fue útil para mí.
sheldonkreger
24

Puedes usar erlcron para eso. Lo usas como

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

:erlcron.cron(job)

A jobes una tupla de 2 elementos. El primer elemento es una tupla que representa la programación del trabajo y el segundo elemento es la función o un MFA (Módulo, Función, Aridad). En el ejemplo anterior, corremos :io.fwrite("It's 2 Thursday morning")cada 2am del jueves.

¡Espero que ayude!

Gjaldon
fuente
Sí, es mejor que nada, gracias.
Dejaré
44
¡De nada! También hay github.com/c-rack/quantum-elixir, que es un elixir lib, si lo prefiere
Gjaldon
6

Usé la biblioteca Quantum Quantum -Elixir .
Siga las instrucciones a continuación.

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

Todo listo. Inicie el servidor ejecutando el siguiente comando.

iex -S mix phoenix.server 
Shashidhar Mayannavar
fuente
Esto es como cronjobs
DarckBlezzer
1

Encuentro un :timer.send_interval/2poco más ergonómico para usar con un GenServerque Process.send_after/4(usado en la respuesta aceptada ).

En lugar de tener que reprogramar su notificación cada vez que la maneja, :timer.send_interval/2establece un intervalo en el que recibe un mensaje sin cesar, sin necesidad de seguir llamando schedule_work()como lo usa la respuesta aceptada.

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

Cada 1000 ms (es decir, una vez por segundo), IntervalServer.handle_info/2se llamará, imprimirá el actual county actualizará el estado del GenServer ( count + 1), dándole un resultado como:

1
2
3
4
[etc.]
s3cur3
fuente
0

Quantum es genial, lo usamos en el trabajo como un reemplazo de cron con un front-end de Phoenix y también agregamos trabajos en tiempo real cual es muy bueno.

gracias
fuente