Wie starte ich die Elixir-Anwendung?

81

Was ist der richtige Weg, um eine Elixir-Anwendung auszuführen?

Ich erstelle ein einfaches Projekt von:

mix new app

und danach kann ich tun:

mix run

Das kompiliert meine App im Grunde einmal. Also, wenn ich hinzufüge:

IO.puts "running"

in lib/app.exIch sehe "running"nur zum ersten Mal, jedes Mal in Folge runtut nichts , es sei denn , es einige Änderungen gibt. Was kann ich als nächstes mit generiert tun app.app?

Natürlich weiß ich, dass ich Folgendes tun kann:

escript: [main_module: App]

in mix.exs, bieten def main(args):und dann:

mix escript.build
./app

aber es ist meiner Meinung nach etwas umständlich.

Es gibt auch so etwas wie:

elixir lib/app.exs

aber es zählt mix.exsoffensichtlich nicht, was für abhängigkeiten in meinem benötigt wird app.

Kamil Lelonek
quelle
1
Wenn Sie ein Elixir-Skript (eine .exsDatei) ausführen möchten, dies jedoch im Kontext Ihrer Mix-App tun, können Sie es ausführen mix run <script>. Siehe mix help runfür weitere Informationen.
Michelle Tilley

Antworten:

103

mix runführt Ihre App aus. Es ist nur so, dass wenn Sie einfach IO.puts "something"eine Datei einfügen, diese Zeile nur zur Kompilierungszeit ausgewertet wird, sie zur Laufzeit nichts tut. Wenn Sie möchten, dass beim Starten Ihrer App etwas gestartet wird, müssen Sie dies in Ihrem Programm angeben mix.exs.

Normalerweise möchten Sie eine Top-Ebene Application, die gestartet wird. Fügen Sie dazu eine modOption hinzu mix.exs:

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

Und dann müssen Sie in diesem Modul einen Rückruf implementieren, der beim Start der Anwendung aufgerufen wird:

defmodule NewMix do
  use Application

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

Der startRückruf sollte tatsächlich Ihren Prozess- oder Überwachungsbaumstamm der obersten Ebene einrichten. In diesem Fall sehen Sie jedoch bereits, dass er bei jeder Verwendung aufgerufen wird mix run, obwohl ein Fehler folgt.

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

In diesem Fall starten wir einen einfachen Prozess in unserem Rückruf, der nur eine Sekunde lang schläft und dann etwas ausgibt - dies reicht aus, um die API des startRückrufs zu erfüllen, aber wir sehen es nicht "done sleeping". Der Grund dafür ist, dass standardmäßig beendet mix runwird, sobald der Rückruf ausgeführt wurde. Damit dies nicht passiert, müssen Sie verwenden mix run --no-halt- in diesem Fall wird die VM nicht gestoppt.

Ein weiterer nützlicher Weg, um Ihre Anwendung zu starten, ist iex -S mix- dies verhält sich ähnlich wie mix run --no-halteine iexShell, öffnet aber auch eine Shell, in der Sie mit Ihrem Code und Ihrer laufenden Anwendung interagieren können.

Paweł Obrok
quelle
4
Okay, das war fast das, was ich brauchte! Können Sie diesen returned a bad value: :okFehler noch erklären , wenn dies nicht der Fall ist Task, oder Agentoder Supervisorusw.? Wie funktioniert das und warum brauchen wir einen separaten Prozess? Warum kann ich nicht einfach ein Skript ausführen, das alles ausführt, was ich brauche?
Kamil Lelonek
18
Ein Anwendungsrückruf muss einen Überwachungsbaum zurückgeben. Wenn Sie keine zurückgeben, schlägt dies fehl. Tatsächlich würde ich sogar den letzten von Paweł gezeigten Ausdruck durch ersetzen : Supervisor.start_link [], strategy: :one_for_one. Das Zurückgeben einer heruntergefahrenen Aufgabe kann dazu führen, dass die Anwendung nach dem Ruhezustand fehlschlägt.
José Valim
1
@squixy einige der Vorteile der Verwendung und Definition von Anwendungen werden hier beschrieben: stackoverflow.com/questions/30422184/…
José Valim
2
Wenn Sie eine lang laufende Anwendung erstellen, möchten Sie fast immer eine Supervisor. Ich habe ein verwendet Task, um das kleinste richtige Programm zu haben, aber wie Jose erwähnt hat, möchten Sie dort Ihren Überwachungsbaum starten.
Paweł Obrok
1
Gute Antwort! Eine Frage. Sie haben geschrieben: "Wenn Sie nur IO.puts "something"eine Datei einfügen, wird diese Zeile nur zur Kompilierungszeit ausgewertet und zur Laufzeit nicht ausgeführt." was scheint dem zu entsprechen, was ich sehe, aber ich verstehe die Logik davon nicht? Warum funktioniert das so?
user2104969
10

Sie können Aufgaben ausführen, indem Mix.TaskSie statt in Ihr Modul importieren mix run.

Ich denke, das ist was du suchst.

Darüber hinaus mix <task.run>können Sie stattdessen einfach ausführen mix, um die Standardaufgabe auszuführen. Einfach default_task: "bot.run"in die Liste von def project do [..] endin aufnehmen mix.exs. Siehe hier .

Holyxiaoxin
quelle