Jak uruchomić aplikację Elixir?

84

Jaki jest prawidłowy sposób uruchamiania aplikacji Elixir?

Tworzę prosty projekt poprzez:

mix new app

a potem mogę:

mix run

który w zasadzie raz kompiluje moją aplikację. Więc kiedy dodam:

IO.puts "running"

w lib/app.exwidzę "running"tylko po raz pierwszy, każdy kolejny runnic nie robi, chyba że istnieją pewne zmiany. Co mogę zrobić dalej z wygenerowanym app.app?

Oczywiście wiem, że mogę:

escript: [main_module: App]

w mix.exs, podaj, def main(args):a następnie:

mix escript.build
./app

ale moim zdaniem jest to trochę kłopotliwe.

Jest też coś takiego:

elixir lib/app.exs

ale nie liczy się to mix.exsoczywiście, co jest potrzebne do zależności w moim app.

Kamil Lelonek
źródło
2
Jeśli chcesz uruchomić skrypt Elixir ( .exsplik), ale zrób to w kontekście swojej aplikacji do miksowania, możesz uruchomić mix run <script>. Zobacz, mix help runaby uzyskać więcej informacji.
Michelle Tilley

Odpowiedzi:

106

mix runuruchamia Twoją aplikację. Chodzi o to, że kiedy po prostu umieścisz IO.puts "something"w pliku, który wiersz jest oceniany tylko w czasie kompilacji, nic nie robi w czasie wykonywania. Jeśli chcesz, aby coś zaczęło się po uruchomieniu aplikacji, musisz to określić w pliku mix.exs.

Zwykle chcesz Applicationzacząć od najwyższego poziomu . Aby to osiągnąć, dodaj modopcję do mix.exs:

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

A następnie w tym module musisz zaimplementować wywołanie zwrotne, które będzie wywoływane przy starcie aplikacji:

defmodule NewMix do
  use Application

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

startZwrotna powinna faktycznie konfiguracja procesu lub korzeń drzewa nadzór najwyższego poziomu, ale w tym przypadku będzie już widać, że jest ona wywoływana za każdym razem korzystać mix run, choć następuje błąd.

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

W tym przypadku rozpoczynamy prosty proces w naszym wywołaniu zwrotnym, który po prostu śpi na jedną sekundę, a następnie wyświetla coś - to wystarczy, aby spełnić API startwywołania zwrotnego, ale tego nie widzimy "done sleeping". Powodem tego jest to, że domyślnie mix runzakończy działanie po zakończeniu wykonywania tego wywołania zwrotnego. Aby tak się nie stało, musisz użyć mix run --no-halt- w tym przypadku maszyna wirtualna nie zostanie zatrzymana.

Innym użytecznym sposobem uruchamiania aplikacji jest iex -S mix- będzie to zachowywało się w podobny sposób, mix run --no-haltale także otwiera iexpowłokę, w której można wchodzić w interakcje z kodem i uruchomioną aplikacją.

Paweł Obrok
źródło
5
W porządku, prawie tego potrzebowałem! Jeszcze jedno, czy możesz wyjaśnić ten returned a bad value: :okbłąd, gdy go nie ma Task, Agentlub Supervisoritp.? Jak to działa i dlaczego potrzebujemy oddzielnego procesu? Dlaczego nie mogę po prostu uruchomić skryptu, który wykonuje wszystko, czego potrzebuję?
Kamil Lelonek
19
Wywołanie zwrotne aplikacji musi zwracać drzewo nadzoru. Jeśli nie zwrócisz, to się nie powiedzie. W rzeczywistości, chciałbym jeszcze wymienić ostatnie wyrażenie przedstawione przez Pawła przez: Supervisor.start_link [], strategy: :one_for_one. Zwrócenie zadania, które zostanie zamknięte, może spowodować awarię aplikacji po uśpieniu.
José Valim
1
@squixy niektóre korzyści płynące z używania i definiowania aplikacji są przedstawione tutaj: stackoverflow.com/questions/30422184/ ...
José Valim,
2
Jeśli tworzysz jakąkolwiek długotrwałą aplikację, prawie zawsze potrzebujesz Supervisor. Użyłem Tasktylko po to, żeby mieć najmniejszy poprawny program, ale jak wspomniał Jose - chcesz tam rozpocząć drzewo nadzoru.
Paweł Obrok
1
Świetna odpowiedź! Jedno pytanie. Napisałeś: „Chodzi tylko o to, że kiedy po prostu umieścisz IO.puts "something"plik w tym wierszu, który jest oceniany tylko w czasie kompilacji, nic nie robi w czasie wykonywania”. co wydaje się odpowiadać temu, co widzę, ale nie rozumiem logiki tego? Dlaczego to działa w ten sposób?
user2104969
10

Możesz uruchamiać zadania, importując je Mix.Taskdo swojego modułu zamiast mix run.

Myślę, że właśnie tego szukasz.

Ponadto zamiast tego mix <task.run>możesz po prostu uruchomić mixzadanie domyślne. Po prostu dodaj default_task: "bot.run"do listy def project do [..] endw mix.exs. Zobacz tutaj .

Holyxiaoxin
źródło