Как работят супервизорите в Elixir, Elixir Community и Phoenix Framework

В Erlang и Elixir надзорните органи са процеси, които управляват дъщерни процеси и ги рестартират, ако възникне грешка. Тази статия разглежда по-отблизо прилагащите надзорници в Elixir.

Но преди да преминете към самите супервизори, е добре да се запознаете с модулите gen_server и supervisor. Можете да се справите и без това, ако вече сте работили с еквивалентни модули Elixir, тъй като те просто предават повиквания към модулите Erlang, без да променят поведението си.

Нека започнем с пример от самата документация на Elixir:

В горния пример методът start_link създава супервизор, а методът init реализира обратното повикване, използвано от поведението от Supervisor. Нека разгледаме по-отблизо Supervisor.

Нека да разгледаме поведението. Операторът use Supervisor се разширява по време на компилиране в поведението, посочено в макроса __using__. Нека да разгледаме кода на макроса __using__ от модула Supervisor в източниците на Elixir .

По време на това писане макросът __using__ изглеждаше така:

@Behaviour проверява супервизора за необходимите функции за обратно извикване и операторът за импортиране зарежда допълнителни функции в MyApp.Supervisor от модула Supervisor.Spec. Тук са дефинирани функциите на работник и надзор. .

Накратко, инструкцията use Supervisor добавя няколко нови функции към проекта и следи за наличието на необходимите функции за обратно извикване.

Супервайзорът започва с извикване на MyApp.Supervisor.start_link. Той се делегира на функцията Supervisor.start_link чрез предаване на връзка към себе си (с помощта на макроса __MODULE__).

Нека да разгледаме внедряването на Supervisor.start_link:

Обърнете внимание, че модулът Elixir делегира повиквания към модула Erlang: supervisor. Но това не е причина за паника! Повярвайте ми и разгледайте източника на Erlang .

Търсейки start_link, ще срещнете оператор за експортиране, който ви позволява да използвате функция извън модула, спецификация, описваща типовете данни, налични за дадена функция, и всъщност самата им реализация:

Виждате ли? Вече нещо познато. Просто изпълняваме gen_server, без да навлизаме в подробности за това как работи. Основното нещо, което трябва да научите тук, е, че надзорните органи са изградени върху модула gen_server, който очаква да види многобройни обратни обаждания.

Методът init представлява много по-голям интерес. Имайте предвид, че въпреки че MyApp.Supervisor съдържа внедряването на функцията init, следващата функция няма да бъде извикана. Ако се върнете към изпълнението на функцията start_link в модула: supervisor от Erlang, ще забележите, че параметърът self е предаден към него. Това означава, че: supervisor.init е функцията, която търсите.

Погледнете изходния му код:

Първо се извиква функцията Mod: init (Args), която от своя страна извиква функцията MyApp.Supervisor.init. Нека да разгледаме още веднъж кода:

Не забравяйте, че работникът и надзорникът са помощници от Supervisor.Spec. Нека не бием около храста, а да преминем към най-важното, тоест, нека разгледаме по-отблизо как всичко това е приложено в Erlang. worker връща child_spec и контролира кортеж по следния начин:, child_specs >> .