Erlang: sestavování aplikací

18. 12. 2014
Doba čtení: 18 minut

Sdílet

Programovací jazyk Erlang je určený k vytváření distrubuovaných systémů pro zpracování velkého množství paralelních úloh. Dnešní díl bude o tom, jak hotové části programu spustit a dozorovat, aby běžely pokud možno na věky věků navzdory případným chybám, a jak to celé pospojovat dohromady a nechat spustit při startu.

Příklady z dnešního dílu budou navazovat na příklad s databází přenesených čísel z minula. Vše potřebné si můžete stáhnout v jednom zipu.

Příklad je třeba zkompilovat a naplnit testovacími daty.

1> c(npdb_mob).
{ok,npdb_mob}
2> c(npdb_mob_db).
{ok,npdb_mob_db}
3> npdb_mob:start_link("data.db").
{ok,<0.47.0>}
4> npdb_mob:fill_random(2000000).
generating 2000000 records
cleaning npdb_mob_ram
cleaning npdb_mob_disk
filling npdb_mob_ram
filling npdb_mob_disk
ok
5> npdb_mob:update(790003366, 104).
ok
6> npdb_mob:lookup(790003366).
{ok,104}
7>

Supervizor

Proces s databázi přenesených čísel z minulého příkladu je obyčejný proces, který je slinkovaný se spouštějícím procesem. Takže ukončení startovacího procesu (v tomto případě Erlang shellu) způsobí i ukončení procesu databáze.

7> 1/0.
** exception error: an error occurred when evaluating an arithmetic expression
     in operator  '/'/2
        called as 1 / 0
8> npdb_mob:lookup(790003366).
** exception error: bad argument
     in function  ets:lookup/2
        called as ets:lookup(npdb_mob_ram,790003366)
     in call from npdb_mob_db:lookup/1 (npdb_mob_db.erl, line 41)
9>

Co s tím? V Erlangu (resp. v knihovně OTP) existuje mechanizmus na dohlížení nad běžícími procesy (tzv. supervize). Myšlenka je opět jednoduchá. Dohlížející proces (supervisor) zná, jak má nastartovat pracovní proces (worker). Ví, jak vypadá jeho startovací funkce (zná trojici modul, funkce, argumenty) a po spuštění je s ním slinkován. Takže pokud se ve workeru stane nějaká nepředloženost (proces skončí), supervisor se to dozví (má nastavený příznak trapexit na true a tudíž není také ukončen, ale dostane od runtime prostředí zprávu) a může zkusit spustit worker proces znovu. Pokud naopak supervisor dostane pokyn k ukončení sama sebe, tak ukončí i svého workera.

Tato jednoduchá myšlenka se komplikuje tím, že jeden supervisor může mít více workerů, ty mohou být průběžně přidávány a odebírány a ještě pár jiných drobností. Nebylo by složité si napsat svého vlastního supervisora. Ale raději použijeme hotového z knihovny OTP (behaviour supervisor).

Toto rozhraní je velmi jednoduché a definuje jen jeden callback (init). Jeho úkolem je vrátit seznam tzv. child specifications (procesů, které mají být spuštěny), jak mají být mezi sebou závislé a jak často zkoušet případné restarty.

V případě databáze přenesených čísel by supervisor mohl vypadat například takto:

%%
%% Supervisor procesu pro databazi prenesenych cisel
%% soubor: npdb_mob_sup.erl
%%
-module(npdb_mob_sup).
-behaviour(supervisor).

-export([start_link/1,  init/1]).

% zkrata pro start supervisoru
start_link (SupArgs) ->
    supervisor:start_link({local, ?MODULE}, ?MODULE, SupArgs).

% callback definujici, co ma supervisor delat
init (SupArgs) ->

    % dekodovani SupArgs
    % zde se predpoklada, ze se jedna o list s jednim prvkem,
    % kterym je nazev souboru
    [FileName] = SupArgs,

    % specifikace procesu
    MobileDb = {
        npdb_mob, {npdb_mob, start_link, [FileName]},
        permanent, 2000, worker, [npdb_mob]
    },

    % restartovaci strategie (n-tice) a za ni
    % nasleduje seznam specifikaci dohlizenych procesu
    {ok, {{one_for_one, 1000, 1}, [MobileDb]}}.

Klčovou věcí je tzv. specifikace procesu. Jedná se o n-tici o šesti prvcích s následujícími významy:

  • Id workeru – identifikátor, přes který se lze na tento worker odkazovat. Libovolná hodnota (ne nutně jen atom).
  • Startovací funkce – n-tice definující startovací funkci a její parametry. Trojice MFA – modul, funkce, argumenty (seznam argumentů).
  • Způsob restartování – za jakých podmínek může být proces znovu spuštěn. Hodnota permanent znamená znovu spustit proces, kdykoli skončí. Může zde být ještě hodnota transient (restart, pouze pokud je proces ukončen chybou) nebo temporary (nikdy nerestartovat).
  • Způsob ukončení – udává, jakým způsobem mý být proces ukončen. Hodnota brutal_kill znamená, že je proces ukončen tím, že je runtime požádán o jeho okamžité „zabití“. Pokud je zde číslo N, (N >0}, supervisor požádá proces o ukončení (je mu zaslán požadavek na ukončení, který vede mimo jiné k zavolání funkce terminate) a proces má maximálně N milisekund na to, aby skončil (pak dojde k „zabití“ jako v předchozím případě). Pokud je zde atom infinity, proces je požádán o ukončení a má na něj k dispozici neomezeně dlouhý čas. Pochopitelně na to pozor, lze tak při troše smůly docílit nepříjemného výpadku.
  • Typ procesu – Pokud je dozorovaným procesem další supervisor, je zde hodnota supervisor. Ostatní procesy zde mají hodnotu worker.
  • Seznam použitých modulů – tento seznam se používá pro zjištění, který proces využívá jaké moduly při výměně kódu. Nepatří sem všechny moduly, ale jen ty, které zajišťují chod procesu (modul s callbacky). V případě, že se jedná o proces typu supervisor, gen_server nebo gen_fsm, je zde příslušný modul. U procesu typu gen_event se zde uvádí atom dynamic.

Pokud všechno dopadlo dobře, návratovou hodnotou funkce init je tzv. restartovací strategie a seznam výše popsaných specifikací pro jednotlivé procesy.

Restartovací strategie říká, co se má stát, pokud dojde k chybě a následnému restartu jednoho z procesů. Může se hodit, že v takovém případě se restartují všechny ostatní procesy (hodnota one_for_all). Nebo naopak aby se restartoval jen ten, který spadl (hodnota one_for_one). Něco mezi tím je hodnota rest_for_one, kdy jsou restartovány jen procesy napravo v seznamu specifikací procesů). Následující dvě čísla uvádějí, jak často za jakou dobu (v milisekundách) je přípustné, aby došlo k restartu (prevence situací, kdy kvůli nějakému chybnému stavu dochází k pádu příliš často).

Procesy jsou po startu supervisora pouštěny v pořadí, v jakém jsou uvedeny v seznamu specifikací a naopak ukončovány jsou v pořadí opačném. Procesy lze kdykoliv nechat restartovat, ukončit nebo dodatečně přidávat a ubírat. Viz dokumentace.

Speciálním případem je supervisor s restartovací strategií simple_one_for_one. Ten se hodí pro situace, kdy je potřeba spouštět mnoho procesů se stejnou startovací funkcí (s různými parametry). Typicky se jedná o spouštění a dozorování procesů na vyřizování jednotlivých transakcí, které přicházejí ze vstupů. Při inicializaci se definuje startovací funkce (a případné konstantní parametry), ale nic se nespustí. Funkce na přidání procesu (start_child) pak spustí proces touto startovací funkcí a případnými dodatečnými parametry. Podrobnosti opět v dokumentaci.

Supervisor může dozorovat jen procesy, které jsou napsány tak, aby obsahovaly jistá rozhraní. Pro začátek stačí že se jedná o procesy typu gen_server, gen_fsm, gen_event nebo jiný supervisor (obecněji se jedná o procesy, které využívají knihovnu proc_lib). Pokud je třeba dozorovat nějaké systémy napsané v „čistém Erlangu“, je pro to určený proces typu supervisor_bridge. Zde je myšlenkou napsat modul s inicializačním a terminačním callbackem, který pustí co je potřeba a vrátí PID procesu, který je třeba sledovat. Pokud je naopak potřeba sledovaný proces ukončit (např. končí celý supervisor), je zavolán ukončovací callback, jehož úkolem je subsystém vypnout. Podrobnosti opět v dokumentaci.

Typem restartovací strategie (one_for_one, one_for_all, rest_for_one) lze určovat závislosti mezi dozorovanými procesy. Tj. pokud je jeden restartován, zda mají být restartovány ostatní nebo ne. U složitějších systémů nemusí stačit mít všechny procesy v jedné skupině. Nic však nebrání tomu mít supervisorů více (pro jednotlivé subsystémy), ty pak pověsit pod společný supervisor a vytvářet tak tzv. stromy supervisorů (supervision tree).

Vraťme se k příkladu s databází přenesených čísel. Ujistěte se, že proces s databází neběží z předchozích pokusů a spusťte si ho pomocí supervisoru.

1> c(npdb_mob_sup).
{ok,npdb_mob_sup}
2> npdb_mob_sup:start_link(["data.db"]).
{ok,<0.40.0>}
3> npdb_mob:lookup(790003366).
{ok,104}
4>

Z předchozích pokusů by měla být v souboru nějaká testovací data, takže by nějaký záznam měl být nalezen.

Vlastní pracovní proces běží pod supervisorem a data jsou zálohována, takže by nemělo vadit jej „sestřelit“, což simuluje situaci, že v něm došlo k nějaké chybě, která způsobila výjimku.

5> npdb_mob:lookup(790004004).
{error,instance}
6> npdb_mob:update(790004004, 104).
ok
7> npdb_mob:lookup(790004004).
{ok,104}
8> Pid = whereis(npdb_mob).
<0.41.0>
9> exit(Pid, kill).
true
10> whereis(npdb_mob).
<0.53.0>
11> npdb_mob:lookup(790004004).
{ok,104}

Na řádcích 5 až 7 byl do databáze vložen nový záznam. Pak bbl funkcí whereis nalezen PID procesu s databází. Ten byl následně na řádku 9 příkazem exit ukončen. Supervisor se postaral o jeho automatické znovuspuštění a příkaz whereis na řádku 10 vrací jiný PID. Vyhledávání v databázi (lookup na řádku 11) díky tomu nadále funguje. Dosažitelnost služby nebyla přerušena. Respektive byla přerušena, a to na okamžik, kdy se načítají záznamy ze zálohy na disku do paměti. Pokud by přišel dotaz během tohoto procesu, mohlo by se stát, že výsledkem bude nenalezení záznamu pro číslo, které v databázi ve skutečnosti je. Čistým řešením by bylo nějak zajistit, aby se s odpověďmi na dotazy po dobu obnovy databáze počkalo, nebo aby se na ně odpovídalo s chybou. Což by šlo například udělat tak, že se data z disku nahrávají do tabulky s dočasným jménem, která se po načtení všech dat přejmenuje (na to jsou v modulu ets funkce). V zájmu nekomplikování příkladu tak učiněno nebylo.

Nyní supervisor dohlíží na pracovní proces, ale kdo dohlíží na supervisora? V současné konfiguraci je supervisor slinkovaný s Erlang shellem a pokud se v něm vyskytne chyba, supervisor a s ním celá databáze skončí.

15> 1/0.

=ERROR REPORT==== 11-Oct-2014::18:03:39 ===
** Generic server npdb_mob_sup terminating
[nasleduje podrobny popis co se stalo a proc supervisor skoncil]

16> npdb_mob:lookup(790004004).
** exception error: bad argument
     in function  ets:lookup/2
        called as ets:lookup(npdb_mob_ram,790004004)
     in call from npdb_mob_db:lookup/1 (npdb_mob_db.erl, line 41)

Hodilo by se něco, co by supervisora spouštělo (a zastavovalo). To něco pochopitelně existuje, jsou to tzv. aplikace.

Aplikace

Aplikace ve smyslu Erlangu je předpis, jak spustit hlavní proces (hlavního supervisora). K tomu jistá infrastruktura s konfigurací, upgrade software za běhu a pod. To platí pro normální aplikace (normal application). Existují ještě tzv. knihovnové aplikace (library application). Ty hlavní supervisor nespouštějí, ale jejich procesy (často typu supervisor) lze zapojit do stromu supervisorů jiné aplikace.

Aplikace je dána názvem (atom) a je definována specifikací aplikace, která je zapsána v tzv. aplikačním souboru (application resource file). V něm je popsáno mimo jiné, v jakém modulu je callback na start hlavního supervisora a callback na úklid při jeho zastavení (behaviour application).

%%
%% Kontrolni soubor pro aplikaci npdb_mob
%% soubor: npdb_mob.app
%%
{application, npdb_mob,
 [{description, "Numbers db"},
  {vsn, "1.0"},
  {modules, [npdb_app,npdb_mob,npdb_mob_db,npdb_mob_sup]},
  {registered, [npdb_mob, npdb_mob_sup]},
  {applications, [kernel, stdlib]},
  {mod, {npdb_mob_app, []}},
  {env, []}]}.

Atributy description a vsn jsou popisné texty. Seznam modulů (modules) a seznam registrovaných procesů (registered) slouží pro automatizované sestavování startovacích scriptů. A atribut application říká, které jiné aplikace musejí být spuštěny před tím, než se spustí tato aplikace.

V atributu mod je uvedeno, který modul implementuje behaviour application a postará se o nahození hlavního supervisora a o případný úklid po jeho vypnutí. Atribut env definuje případné prostředí (konfiguraci) aplikace.

Odbočka k formátu konfiguračních souborů. V Erlangu se pro zápis různých konfigurací používají různé více či méně složitě do sebe zanořené listy a n-tice, které pak mohou obsahovat skalární hodnoty (čísla a atomy, případně string, což je vlastně seznam čísel). V souboru lze libovolně odsazovat a psát komentáře jako ve zdrojových souborech Erlangu. Formát vzdáleně připomíná JSON. Na konci struktury je povinná tečka. Soubory v takovém formátu lze velmi snadno načíst a rozparsovat zavoláním funkce file:consult/1. Výstupem je rovnou v souboru zapsaná struktura. Může se hodit, pokud budete přemýšlet nad tím, jak zrealizovat konfigurační soubor.

Aplikační modul pak vypadá následovně:

%%
%% Startovaci funkce aplikace prenesenych cisel.
%% soubor: npdb_mob_app.erl
%%
-module(npdb_mob_app).
-behavior(application).
-export([start/2, stop/1]).

start(_Type, _AppArgs) ->
    case application:get_env(file_name) of
        {ok, FileName} ->
            npdb_mob_sup:start_link([FileName]);
    undefined -> {error, {no_data_db_file, "Missing file_name key in the application env (config issue?)"}}
    end.

stop(_State) ->
    ok.

Aplikační soubor npdb_mob.app je třeba umístit tam, kde jsou binární soubory modulů (.beam soubory). V tomto příkladě tam, kde jsou i zdrojové soubory. Aplikační modul npdb_mob_app.erl je třeba přeložit. Pak je možno zkusit spustit aplikaci pomocí k tomu určené funkce application:start.

1> c(npdb_mob_app).
{ok,npdb_mob_app}
2> application:start(npdb_mob).
{error,{{no_data_db_file,"Missing file_name key in the application env (config issue?)"},
        {npdb_mob_app,start,[normal,[]]}}}
3>
=INFO REPORT==== 14-Oct-2014::19:08:31 ===
    application: npdb_mob
    exited: {{no_data_db_file,"Missing file_name key in the application env (config issue?)"},
             {npdb_mob_app,start,[normal,[]]}}
    type: temporary

Spuštění se nepovedlo, protože tzv. prostředí aplikace (environment) neobsahuje očekávaný klíč file_name. V takovém případě startovací funkce vrací chybu, což se projeví v návratové hodnotě funkce application:start a zároveň je to vidět v logovací zprávě.

Jak dostat do proměnných aplikace požadovanou hodnotu? Možností je několik. Je možné zapsat požadovanou hodnotu do klíče env v aplikačním souboru. A to ve formě property listu (list n-tic {key, value}). V tomto případě:

{env, [{file_name, "data.db"}]}

Pozor, v případě změny aplikačního souboru nestačí pouze uložit změny. Je třeba případnou předchozí specifikaci aplikace vymazat zavoláním funkce application:unload/1.

Další možností je nastavit hodnotu prostředí přímo zavoláním funkce application:set_env.

4> application:set_env(npdb_mob, file_name, "data.db").
ok
5> application:start(npdb_mob).
ok
6> npdb_mob:lookup(790003366).
{ok,104}

Proměnné aplikací lze také nastavit konfigurací nebo parametry spuštění runtime prostředí (příkaz erl – viz dokumentace).

Spouštění při startu

Jak ale spouštět aplikace? Nejjednodušší je si na to napsat pomocný modul, který se postará o nastavení proměnné file_name a spustí aplikaci.

%%
%% Rozhrani pro zapnuti a vypnuti aplikace a pro
%% API pro vyhledavani v databazi
%% soubor: npdb.erl
%%
-module(npdb).
-export([start/1, lookup/1, stop/0]).

% startovaci funkce - nastavi se hodnota do enviromentu
% aplikace a nasledne se spusti
start(FileName) ->
    application:set_env(npdb_mob, file_name, FileName),
    application:start(npdb_mob).

% vypinaci funkce
stop() ->
    application:stop(npdb_mob).

% zkratka pro vybrane casti uzivatelskeho API
lookup(Msisdn) ->
    npdb_mob:lookup(Msisdn).

Pak lze využít toho, že příkazu erl lze zadat, jakou funkci má po startu spustit. A to např. parametrem -run. Za ním následuje modul, funkce a případné argumenty. Argumenty se předávají jako string (pokud by se místo -run použil přepínač -s, tak jako atomy). Pro start pomocí funkce npdb:start(„data.db“) je třeba spustit následující.

$ erlc npdb.erl
$ erl -run npdb start "data.db"
Eshell V5.10.1  (abort with ^G)
1> npdb:lookup(790003366).
{ok,104}

Pro řadu systémů to takto může stačit. Erlang/OTP framework nabízí využít tzv. release. Myšlenkou je do jistého textového souboru zapsat, jaké aplikace mají být při startu runtime prostředí spuštěny. Z tohoto textového souboru lze pak nechat vygenerovat bootovací soubor a ten předat příkazu erl v parametrech příkazové řádky. Aplikace si načtou konfiguraci z proměnných prostředí (ty lze ovlivňovat parametry příkazové řádky) a pak dělají, co mají.

Release umožňují řídit upgrade software za běhu, a to včetně fallbacků, kdy chyba při upgrade vede k tomu že se doposud provedené změny uvedou zpět do původní verze, aby se služba pokud možno nezastavila. Do toho se může stát, že aplikace je distribuovaná (běží na více uzlech). Je asi tušit, že tyto release mou být docela složité. Pro základní představu bude následovat jen velmi jednoduchá forma, kdy je za úkol při startu automaticky spustit požadovanou aplikaci a předat jí konfiguraci.

Telegraficky:

1. zjistit si, jaké aplikace a jejich verze běží v „prázdném“ Erlangu.

1> application:which_applications().
[{stdlib,"ERTS  CXC 138 10","1.19.1"},
 {kernel,"ERTS  CXC 138 10","2.16.1"}]

2. Napsat release soubor, který kromě výše uvedených aplikací spustí aplikaci npdb_mob.
Pozor, čísla verzí knihoven v souboru musejí sedět na čísla z výpisu aplikací výše
(může se lišit v různých verzích Erlangu).

%%
%% Release soubor pro npdb_mob aplikaci
%% soubor: npdb_mob.rel
%%
{release, {"Number portability database", "R1"}, {erts, "5.10.1"},
  [{kernel, "2.16.1"},
   {stdlib, "1.19.1"},
   {npdb_mob, "1.0"}]}.

3. Nechat release soubor zkompilovat nástrojem systools:make_script/2 (warning ignorovat).

1> systools:make_script("npdb_mob", [local]).
*WARNING* : Missing application sasl. Can not upgrade with this release
ok

4. Spustit Erlang a dát mu jako -boot parametr nově vzniklý boot soubor npdb_mob.boot (bez koncovky).

$ erl -boot npdb_mob

=INFO REPORT==== 17-Oct-2014::00:05:19 ===
    application: npdb_mob
    exited: {{no_data_db_file,"Missing file_name key in the application env (config issue?)"},
             {npdb_mob_app,start,[normal,[]]}}
    type: permanent

5. Nepovedlo se to, ještě je třeba nastavit parametr do environmentu aplikace. To se
dá např. udělat argumenty, konkrétně přepínačem -Application key value, kde Application je název aplikace.
Drobná past je v tom, že parametr se předává jako hodnota, která je Erlangem vyhodnocována a může v něm být i nějaká složená struktura.
V našem případě se jedná o řetězec s názvem souboru, takže je třeba jej zadat i s dvojitými uvozovkami (nenechat si je sebrat shellem).

$ erl -boot npdb_mob -npdb_mob file_name '"data.db"'
Eshell V5.10.1  (abort with ^G)
1> application:which_applications().
[{npdb_mob,"Number portability DB","1.0"},
 {stdlib,"ERTS  CXC 138 10","1.19.1"},
 {kernel,"ERTS  CXC 138 10","2.16.1"}]
2> npdb:lookup(790003366).
{ok,104}

Spuštěné aplikace (které mají strom supervisorů) a jejich procesy lze graficky zobrazit programem Observer (observer:start()).

Zbývá ještě vyřešit, jak Erlang spustit bez shellu a pokud možno jako daemona. To první se dá vyřešit parametrem -noshell. Na to druhé by se mohl hodit parametr -detached (nemám zkušenosti, osobně používám pro zajištění běhu program Daemontools). Při vytváření start a stop skriptů možná narazíte na komplikaci se signály od operačního systému. Erlang runtime prostředí na ně nereaguje (nelze na ně reagovat v kódu aplikace). Dle slov jednoho z autorů se jedná o příliš specifickou vlastnost operačního systému. Proto je třeba vypnutí (stop script) vyřešit nějakou Erlang cestou. Např. se připojit k runtime prostředí (nebyla o tom řeč jak na to) a v něm zavolat funkce, které se postarají o korektní zastavení všeho co je třeba. Pokud je třeba reagovat na signály, dá se Erlang spustit jako potomek nějakého shellu, signály chytat v shellu a jako reakci na ně zavolat výše naznačené procesy, které nakonec povedou ke korektnímu vypnutí.

Na téma automatické spouštění kódu při startu ještě stojí za zmínku soubor .erlang. Ten může být umístěný jak v $HOME, tak v aktuálním adresáři. Při startu se spustí kód v něm obsažený. Zda vždy a za všech okolností nevím, nepoužívám jej.

Struktura aplikace

Kód který jsme doposud psali, se nacházel v aktuálním adresáři. Zde se kompilováním vytvářely ze zdrojových souborů .beam soubory a runtime prostředí si je zde dokázalo nalézt. Vyhledávání souborů modulů se provádí v různých adresářích a tento seznam lze obohatit přepínači -pa a -pz (přidání adresáře na začátek nebo na konec seznamu).

Mít všechny moduly v několika málo adresářích může být poněkud nepraktické a pokud se podíváte do nějakých stávajících aplikací, zjistíte, že obsahují jistou adresářovou strukturu. OTP aplikace se nacházejí v adresáři s názvem aplikace-verze (např. npdb-1.0). Pokud obsahují podadresář ebin, je tento přidán do cesty kde se hledají moduly. Kam ale umisťovat adresáře s aplikacemi, aby je systém nalezl? Buď třeba symlinkem tam, kde jsou systémové knihovny (code:root_dir() + „/lib“), nebo (lépe) je možno přidat adresáře pro aplikace nastavením proměnné prostředí ERL_LIBS.

$ echo $ERL_LIBS
/home/lojza/erlang_libs

To je poměrně zásadní poznatek, pokud chcete začít používat aplikace třetích stran, nebo si vytvářet vlastní. Cest pro umisťování aplikací může být pochopitelně více. Pak se oddělují dvojtečkou (ve Windows středníkem).

Kromě zmíněného adresáře ebin aplikace obsahují adresář src na zdrojové soubory, include na sdílené hlavičkové soubory, doc na dokumentaci, tests na automatizované testy a pod.

Do hlavičkových souborů aplikací v adresáři include se lze dosat takto:

-include_lib("nejaka_aplikace/include/potrebna_makra_a_recordy.hrl").

Přičemž název aplikace neobsahuje verzi, i když ji příslušný adresář s aplikací obsahuje. Pokud je zde jedna aplikace ve více verzích, bere se ta nejvyšší.

Aplikace může nepovinně obsahovat adresář priv, který je dosažitelný pomocí funkce code:priv_dir/1. Může se hodit pro různé neerlangovské zdroje aplikace typu skripty, obrázky a pod.

Zbývá otázka, jak proměnit zdrojové soubory v adresáři src ve zkompilované binární soubory a dostat je do adresáře ebin. Zde není jednotná metodika. Někomu se líbí klasické Makefile soubory, jiný dává přednost nástroji rebar (není součást distribuce Erlang). Záleží na vkusu.

Archiv s příklady obsahuje aplikaci npdb rozdělenou do výše uvedených adresářů.

Závěr

Úspěšným vytvořením aplikace bych rád ukončil tento jemný úvod do jazyka Erlang. Nedotkli jsme se všech oblastí. Ze syntaxe např. anonymní funkce či procházení listů, z vlastností runtime prostředí zejména distribuované aplikace (komunikace po síti mezi jednotlivými Erlang uzly), způsoby, jak může Erlang komunikovat s jinými programy v heterogenních systémech nebo detailně popsat možnosti upgrade software za běhu a jiné. Ale věřím, že základy a hlavní myšlenky zde padly. Vážnější výklad na téma Erlang je spíše na knihu než na pár článků. Jako pro každý jiný programovací jazyk, pokud chcete více než jen „Hello world!“

Pro další poznání doporučuji si pořídit nějakou knihu a poctivě ji přečíst. Naštěstí existují. Například:

  • Programming Erlang od Joe Armstronga (autor Erlangu). Zajímavá je jeho disertační práce Making reliable distributed systems in the presence of sofware errors (volně dostupné) – historické a jiné souvislosti (z pohledu „Computer science“), případové studie.
  • Erlang Programming (Francesco Cesarini, Simon Thompson)
  • Learn you some Erlang for great good (Fred Hébert) – dostupné online. Stejný autor nedávno zveřejnil knihu Stuff Goes Bad: Erlang in Anger – soubor praktických zkušeností s psaním a provozováním programů v Erlangu, co se může pokazit a kde a jak hledat příčiny potíží (volně dostupné).
  • Concurrent Programming in ERLANG (Joe Armstrong a kolektiv) – „prakniha“ od hrdinů z videa z prvního dílu

Dobrým zdrojem pro rozšíření si obzorů, co se s Erlangem dá podnikat, mohou být materiály z konferencí, např. Erlang factory.

bitcoin_skoleni

Nelze opomenout oficiální dokumentaci. Přijde mi dobrá a kromě referenčních popisů jednotlivých modulů a funkcí obsahuje pro řadu kapitol průvodce, kde je vysvětlen princip dané knihovny a záměry autorů. Jak asi bylo vidět, v jazyce Erlang se programy zapisují velmi stručně a výstižně. Ne jinak je to s jeho dokumentací. Našel jsem v ní všechno, na čem jsem se kdy zasekl, ale vyplatí se ji číst velmi pozorně.

Hodně zajímavých a úspěšných projektů spojených s Erlangem.

Autor článku