Podczas 21 odcinka stworzyć kilka instancji PingPong.Server w elixir. Wtedy też wykorzystaliśmy jeden sposób, którego nie opisałem i obiecałem, że kiedyś opiszę. A więc to kiedyś właśnie nastąpiło :) Dla niewtajemniczonych w jednej z aplikacji chcieliśmy stworzyć dwa razy ten sam GenServer, przy czym wciąż chcieliśmy się do niego odwoływać po nazwie zamiast posiadać gdzieś zapisany PID. Czyli by za pomocą jak najprostszego kodu móc wywołać ping i uzyskać pong.

Nasza domyślna implementacja PingPong.Server na start_link/0 wykonywała kod:

GenServer.start_link(__MODULE__, 0, name: :pingpong)

Który bindował GenServer do aktualnego modułu (__MODULE__), ustawiał stan początkowy na 0 oraz nadawał nazwę naszego serwera jako :pingpong. To ostatnie pozwalało nam na wykonywanie kodu:

GenServer.call(:pingpong, {:ping, "ping"})

Który wysyłał wiadomość do serwera :pingpong o treści ping. Gdybyśmy nie nadali mu nazwy :pingpong, musielibyśmy przechować wynik naszego start_link/0, lub pozbyć się abstrakcji PingPong.start_link/3:

pid = GenServer.start_link(__MODULE__, 0)

Dzięki temu pid'owi jesteśmy wstanie wywołać nasz serwer:

GenServer.call(pid, {:ping, "ping"})

Oczywiście, mogliśmy to zrobić wcześniej posiadając nazwany serwer, jednak, mielibyśmy kłopoty, gdybyśmy chcieli takich serwerów stworzyć dwa lub nawet trzy. A to wszystko przez to, że nazwa został już zarejestrowana/wykorzystywana. Opcja z PID pozwala nam mieć wiele serwerów PingPong.Server, jednak utrudnia ona nam ich zarządzanie.

Dla przykładu, jak mieliśmy nadzorcę, to nasz PingPong.Server był tworzony z poziomu inicjalizacji nadzorcy. Co powoduje, że wiedza o PID po prostu zniknie. Metoda ping w PingPong.Server zaś przestanie mieć sens, bo nie jesteśmy wstanie tego wysłać – nie znamy ani pidu ani nie mamy nazwy.

Właśnie dla takich sytuacji dostępne są trzy rozwiązania z którch możemy skorzystać. Dwa rozwiązania możemy wykorzystać zarówno w iex jak i w mix, zaś trzecie i ostatnie jedynie w mix. Jedną opcję już znamy i jest to rejestrowanie serwera po atom’ie. Czyli dosłownie tak jak to zrobiliśmy z :pingpong.

Dziś zajmiemy się drugą opcją – modułem :global. Wiedza ta przyda się bardzo przy tworzeniu Supervisors i GenServers w BitTorrent gdzie dosłownie o taki sam problem zahaczymy. A za tydzień sięgniemy do opcji trzeciej i ostatniej.

:global

O :global jest cicho – albo ja nie potrafiłem szukać – w postach o elixir, jako, że jest to moduł typowo erlangowy. A dokładniej jest to globalny rejestr nazw. Serwer ten jest startowany od razu z nodem i umożliwia on komunikacje cross nodową – rozproszoną. Czyli pozwala nam na znalezienie serwera który może być na zupełnie innym komputerze lub w innym procesie terminala.

To jak on działa i co on daje, pozostawiam waszej dociekliwości :) dla nas jedyne ważne jest to w tym przypadku, że on istnieje i implementuje on metody które GenServer potrzebuje by móc rejestrować nazwy bardziej globalnie niż nasz PingPong.Server. Tracimy w tym momencie metodę ping/0 w takiej postaci jak aktualnie ją mamy, ale też możemy ją ciutkę przerobić – zaraz pokaże jak.

Ogólnie, rozchodzi się wszystko o to, że przy start_link/3 ostatni parametr wygląda następująco:

{:global, name}

To spowoduje, że nasz serwer zostanie zarejestrowany w globalnym module i będzie miał nazwę name. Teraz przy słaniu wiadomości wystarczy podać:

GenServer.call({:global, name}, {:ping, "ping"})

A więc nasz ping trzeba zamienić na:

def ping(name) do
    GenServer.call({:global, name}, {:ping, "ping"})
end

CIEKAWOSTKA: jak nadawaliśmy swoją nazwę za pomocą atomu, to elixir zamieniał to na {:local, name}, a więc prawie na to samo co :global, tylko, ze lokalnie (na danym komputerze, na danym node).

Podsumowanie

W ogóle pominąłem kwestię co to jest node i jak on wygląda i jakie ma właściwości. Wrócę do tego. Ale chciałem tylko pokazać, że mamy kilka sposobów rejestrowania GenServer w aplikacji. Każdy ma swoje plusy i minusy każdy też ma innych zasięg.

Dziś była opcja z :global rejestracją nazw tak by każdy w sieci mógł z niej skorzystać. Co prawda to nie rozwiązuje problemu z :pingpong a wręcz przeciwnie powoduje, że nie będziemy mogli użyć :pingpong nigdzie w sieci, jednak jest to też krok do tego by opisać ostatnie rozwiązanie które ten problem już rozwiązuje.

Do przeczytania jak zwykle jutro, a o elixirze za tydzień! :)

1 KOMENTARZ

Comments are closed.