¿Cómo ejecutar una aplicación Elixir?

81

¿Cuál es la forma correcta de ejecutar una aplicación Elixir?

Estoy creando un proyecto simple por:

mix new app

y después de eso puedo hacer:

mix run

que básicamente compila mi aplicación una vez. Entonces cuando agrego:

IO.puts "running"

en lib/app.exVeo "running"solo por primera vez, cada consecutivo runno hace nada a menos que haya algunos cambios. ¿Qué puedo hacer a continuación con generado app.app?

Por supuesto que sé que puedo hacer:

escript: [main_module: App]

en mix.exs, proporcionar def main(args):y luego:

mix escript.build
./app

pero es un poco engorroso en mi opinión.

También hay algo como:

elixir lib/app.exs

pero mix.exsobviamente no cuenta , lo cual es necesario para las dependencias en my app.

Kamil Lelonek
fuente
1
Si desea ejecutar un script de Elixir (un .exsarchivo) pero hacerlo en el contexto de su aplicación mixta, puede ejecutar mix run <script>. Consulte mix help runpara obtener más información.
Michelle Tilley

Respuestas:

103

mix runejecuta su aplicación. Es solo que cuando simplemente coloca IO.puts "something"en un archivo esa línea solo se evalúa en tiempo de compilación, no hace nada en tiempo de ejecución. Si desea que algo comience cuando inicie su aplicación, debe especificarlo en su mix.exs.

Por lo general, desea un nivel superior Applicationque comience. Para lograrlo, agregue una modopción a su mix.exs:

def application do
  [
    # this is the name of any module implementing the Application behaviour
    mod: {NewMix, []},
    applications: [:logger]
  ]
end

Y luego, en ese módulo, debe implementar una devolución de llamada que se llamará al inicio de la aplicación:

defmodule NewMix do
  use Application

  def start(_type, _args) do
    IO.puts "starting"
    # some more stuff
  end
end

La startdevolución de llamada debería configurar su proceso de nivel superior o la raíz del árbol de supervisión, pero en este caso ya verá que se llama cada vez que lo usa mix run, aunque seguido de un error.

def start(_type, _args) do
  IO.puts "starting"
  Task.start(fn -> :timer.sleep(1000); IO.puts("done sleeping") end)
end

En este caso, estamos iniciando un proceso simple en nuestra devolución de llamada que solo duerme durante un segundo y luego genera algo; esto es suficiente para satisfacer la API de la startdevolución de llamada, pero no vemos "done sleeping". La razón de esto es que, por defecto, se mix runcerrará una vez que la devolución de llamada haya terminado de ejecutarse. Para que eso no suceda, debe usar mix run --no-halt; en este caso, la máquina virtual no se detendrá.

Otra forma útil de iniciar su aplicación es iex -S mix: esto se comportará de manera similar mix run --no-haltpero también abrirá un iexshell donde puede interactuar con su código y su aplicación en ejecución.

Paweł Obrok
fuente
4
¡Muy bien, eso es casi lo que necesitaba! Una cosa más, ¿puede explicar este returned a bad value: :okerror cuando no hay Task, o Agento Supervisoretc? ¿Cómo funciona eso y por qué necesitamos un proceso separado? ¿Por qué no puedo ejecutar un script que ejecute todo lo que necesito?
Kamil Lelonek
18
Una devolución de llamada de la aplicación debe devolver un árbol de supervisión. Si no devuelve uno, fallará. De hecho, yo incluso sustituir la última expresión mostrada por Paweł por: Supervisor.start_link [], strategy: :one_for_one. Devolver una tarea que se apaga puede hacer que la aplicación falle después de dormir.
José Valim
1
@squixy, algunos de los beneficios de usar y definir aplicaciones se describen aquí: stackoverflow.com/questions/30422184/…
José Valim
2
Si está creando cualquier tipo de aplicación de larga duración, casi siempre querrá un Supervisor. Usé Tasksolo para tener el programa correcto más pequeño, pero como mencionó José, desea comenzar su árbol de supervisión allí.
Paweł Obrok,
1
¡Gran respuesta! Sin embargo, una pregunta. Escribiste "Es solo que cuando simplemente colocas IO.puts "something"en un archivo esa línea solo se evalúa en tiempo de compilación, no hace nada en tiempo de ejecución". que parece corresponde a lo que estoy viendo pero no entiendo la lógica de esto? ¿Por qué funciona de esa manera?
user2104969
10

Puede ejecutar tareas importando Mix.Tasken su módulo en lugar de mix run.

Creo que esto es lo que estás buscando.

Además de eso, en lugar de mix <task.run>, simplemente puede ejecutar mixpara ejecutar la tarea predeterminada. Simplemente agréguelo default_task: "bot.run"a la lista de def project do [..] endin mix.exs. Consulte aquí .

holyxiaoxin
fuente