Supervisors-prosessit ja sovellusrakenne
Suunnitelkaa vikasietoisia sovelluksia supervisoreiden avulla valvomalla ja käynnistämällä prosesseja uudelleen.
Supervisors-prosessit ja sovellusrakenne on ilmainen Elixir ja Phoenix: skaalautuva backend-kehitys-oppitunti CoddyKitissä. Tämä on oppitunti 3/4. Voit lukea koko oppitunnin alta ilmaiseksi ja harjoitella sen jälkeen käytännössä selaimessa sisäänrakennetulla koodieditorilla ja ympäri vuorokauden käytettävissä olevan tekoälytuutorin avulla. Oppitunti kuuluu Elixir ja Phoenix: skaalautuva backend-kehitys-oppimispolkuun, ja edistymisesi synkronoituu verkon ja CoddyKit-sovelluksen välillä. Elixir ja Phoenix: skaalautuva backend-kehitys-kurssilla on yhteensä 4 oppituntia.
Vikasietoisten järjestelmien rakentaminen
Rinnakkaisissa sovelluksissa voi tapahtua virheitä. Prosessit saattavat kaatua odottamattomien virheiden tai ulkoisten ongelmien vuoksi.
Vikasietoisuus tarkoittaa järjestelmän kykyä jatkaa toimintaansa, vaikka sen komponentteja vikaantuisi. Elixir noudattaa ”anna kaatua” -ajattelutapaa: jokaisen kaatumisen estämisen sijaan keskitytään palautumaan niistä hallitusti.
Prosessien suojelijat
Tässä kohtaa supervisorit astuvat kuvaan! Supervisor on erityinen prosessityyppi, joka on suunniteltu valvomaan muita prosesseja (”lapsiprosessejaan”).
- Jos lapsiprosessi kaatuu, supervisor käynnistää sen automaattisesti uudelleen.
- Näin sovellus pysyy vakaana ja käytettävissä.
- Supervisorit muodostavat vikasietoisten Elixir-sovellusten selkärangan.
Ensimmäinen supervisorinne
Määritetään yksinkertainen supervisor-moduuli. Se käyttää Supervisor-käyttäytymismallia samalla tavoin kuin GenServer käyttää GenServer-käyttäytymismallia.
init/1-takaisinkutsussa määritetään valvottavat lapsiprosessit ja uudelleenkäynnistysstrategia.
defmodule MySupervisor do
use Supervisor
def start_link(init_arg) do
Supervisor.start_link(__MODULE__, init_arg, name: __MODULE__)
end
@impl true
def init(_init_arg) do
# No children yet, just the supervisor itself
children = []
Supervisor.init(children, strategy: :one_for_one)
end
end
# --- Main execution part ---
# This simulates starting the supervisor and checking its status.
# In a real app, this would be part of an Application's start/2.
IO.puts("Attempting to start MySupervisor...")
{:ok, supervisor_pid} = MySupervisor.start_link([])
IO.puts("MySupervisor started with PID: #{inspect(supervisor_pid)}")
# Check if the supervisor process is alive
if Process.alive?(supervisor_pid) do
IO.puts("Supervisor is alive!")
else
IO.puts("Supervisor is NOT alive!")
endValvontastrategioiden ymmärtäminen
Supervisoreilla on erilaisia strategioita lapsiprosessien virheiden käsittelyyn:
:one_for_one: Käynnistää uudelleen vain kaatuneen lapsiprosessin. Tämä on oletusstrategia ja yleisin vaihtoehto.:one_for_all: Jos jokin lapsiprosessi kaatuu, kaikki muut lapsiprosessit lopetetaan ja sen jälkeen kaikki lapsiprosessit käynnistetään uudelleen.:rest_for_one: Jos lapsiprosessi kaatuu, se ja kaikki sen jälkeen käynnistetyt lapsiprosessit lopetetaan ja käynnistetään sitten uudelleen.
Oikean strategian valinta riippuu prosessien välisistä riippuvuuksista.
Valvottavien lapsiprosessien lisääminen
Jotta supervisorista olisi hyötyä, se tarvitsee lapsiprosesseja! Lapsiprosessit määritetään käyttämällä funktiota Supervisor.child_spec/2, joka kertoo supervisorille, miten prosessi käynnistetään ja miten sitä hallitaan.
Tässä määritämme yksinkertaisen MyWorker-GenServerin ja lisäämme sen supervisorimme lapsiprosessiksi.
defmodule MyWorker do
use GenServer
def start_link(_opts) do
GenServer.start_link(__MODULE__, :ok, name: __MODULE__)
end
@impl true
def init(:ok) do
IO.puts("MyWorker started!")
{:ok, %{}}
end
@impl true
def handle_call(:crash, _from, state) do
IO.puts("MyWorker is crashing!")
exit(:bad_state) # Simulate a crash
{:reply, :ok, state} # This line won't be reached
end
end
defmodule MySupervisorWithWorker do
use Supervisor
def start_link(init_arg) do
Supervisor.start_link(__MODULE__, init_arg, name: __MODULE__)
end
@impl true
def init(_init_arg) do
children = [
# Define our worker as a child process
Supervisor.child_spec(MyWorker, id: MyWorker)
]
Supervisor.init(children, strategy: :one_for_one)
end
end
# --- Main execution part ---
IO.puts("Starting supervisor with worker...")
{:ok, supervisor_pid} = MySupervisorWithWorker.start_link([])
IO.puts("Supervisor PID: #{inspect(supervisor_pid)}")
# Get the worker's PID
worker_pid = Process.whereis(MyWorker)
IO.puts("Initial MyWorker PID: #{inspect(worker_pid)}")
if Process.alive?(worker_pid) do
IO.puts("Worker is alive and supervised.")
else
IO.puts("Worker did not start correctly.")
endVikasietoisuus käytännössä
Seuraavaksi tarkastellaan supervisorin toimintaa käytännössä! Kaadamme tarkoituksella MyWorker-prosessin, ja supervisor käynnistää sen automaattisesti uudelleen.
Huomatkaa, että työntekijän prosessitunniste (PID) muuttuu, mikä osoittaa, että uusi prosessi luotiin.
defmodule MyWorker do
use GenServer
def start_link(_opts) do
GenServer.start_link(__MODULE__, :ok, name: __MODULE__)
end
@impl true
def init(:ok) do
IO.puts("MyWorker started!")
{:ok, %{}}
end
@impl true
def handle_call(:crash, _from, state) do
IO.puts("MyWorker is crashing!")
exit(:bad_state) # Simulate a crash
{:reply, :ok, state} # This line won't be reached
end
def crash_it do
GenServer.call(__MODULE__, :crash)
end
end
defmodule MySupervisorWithWorker do
use Supervisor
def start_link(init_arg) do
Supervisor.start_link(__MODULE__, init_arg, name: __MODULE__)
end
@impl true
def init(_init_arg) do
children = [
Supervisor.child_spec(MyWorker, id: MyWorker)
]
Supervisor.init(children, strategy: :one_for_one)
end
end
# --- Main execution part ---
IO.puts("Starting supervisor with worker...")
{:ok, _supervisor_pid} = MySupervisorWithWorker.start_link([])
worker_pid_before_crash = Process.whereis(MyWorker)
IO.puts("Worker PID before crash: #{inspect(worker_pid_before_crash)}")
# Crash the worker
IO.puts("Attempting to crash the worker...")
MyWorker.crash_it()
:timer.sleep(100) # Give supervisor a moment to restart
worker_pid_after_crash = Process.whereis(MyWorker)
IO.puts("Worker PID after crash: #{inspect(worker_pid_after_crash)}")
if worker_pid_before_crash != worker_pid_after_crash && Process.alive?(worker_pid_after_crash) do
IO.puts("Worker was restarted by the supervisor! New PID detected.")
else
IO.puts("Worker was NOT restarted, or PID remained the same (unexpected).")
endElixir-sovellukset: ylin taso
Supervisorit hallitsevat yksittäisiä prosesseja, kun taas Elixir-sovellus on Elixir-järjestelmän koodin ja prosessien ylin yksikkö.
Se tarjoaa jäsennellyn tavan:
- Ryhmitellä toisiinsa liittyviä moduuleja ja prosesseja.
- Määrittää, miten järjestelmä käynnistyy ja sammuu.
- Hallita asetuksia ja riippuvuuksia.
`Application`-käyttäytymismalli
Jokaisella Elixir-sovelluksella on yleensä pääsovellusmoduuli, joka käyttää use Application-määritystä.
Tärkein takaisinkutsu on start/2, jota kutsutaan sovelluksen käynnistyessä. Tässä käynnistetään yleensä ylätason supervisor, joka käynnistää sitten rekursiivisesti kaikki järjestelmän muut prosessit.
defmodule MyApp.Application do
use Application
# This is the entry point for your application.
# It starts the top-level supervisor.
@impl true
def start(_type, _args) do
children = [
# In a real app, you'd start your main supervisor here.
# For example: Supervisor.child_spec(MySupervisorWithWorker, id: MySupervisorWithWorker)
]
# Start a supervisor that will supervise other processes/supervisors
opts = [strategy: :one_for_one, name: MyApp.Supervisor]
Supervisor.start_link(children, opts)
end
end
# --- Main execution part ---
# This part simulates how an application would be started.
# In a real Mix project, 'mix run --no-halt' would call MyApp.Application.start/2
IO.puts("Simulating application start...")
{:ok, pid} = MyApp.Application.start(:normal, [])
IO.puts("Application top-level supervisor started with PID: #{inspect(pid)}")
if Process.alive?(pid) do
IO.puts("Application supervisor is active.")
else
IO.puts("Application supervisor failed to start.")
endHierarkkiset valvontapuut
Monimutkaisissa sovelluksissa ei yleensä ole vain yhtä supervisoria. Sen sijaan luodaan valvontapuu, jossa supervisorit voivat valvoa muita supervisoreita.
- Tämä auttaa järjestämään sovelluksen loogisiin yksiköihin.
- Järjestelmän eri osilla voi olla erilaiset uudelleenkäynnistysstrategiat.
- Jos tärkeä komponentti vikaantuu, sen supervisor voi käynnistää sen uudelleen vaikuttamatta järjestelmän muihin, toisiinsa liittymättömiin osiin.
Supervisorien tarkistus
On aika testata nopeasti, miten hyvin ymmärrätte supervisorien strategiat!
Oppitunnin yhteenveto
Hienoa! Olette oppineet, miten Elixir rakentaa vikasietoisia sovelluksia:
- Supervisorit valvovat prosesseja ja käynnistävät ne uudelleen vikaantuessa.
- Erilaiset valvontastrategiat (
:one_for_one,:one_for_all,:rest_for_one) määrittävät, miten virheet käsitellään. - Elixir-sovellukset tarjoavat ylätason rakenteen, käynnistävät supervisorit ja muodostavat valvontapuita.
Nämä käsitteet ovat olennaisia vankkojen ja vikasietoisten Elixir-järjestelmien rakentamisessa.
Opi Elixir tekoälytuutorin avulla — ilmaiseksi
Kirjoita ja suorita oikeaa koodia selaimessa, saa välitöntä apua tekoälytuutorilta ympäri vuorokauden ja jatka siitä, mihin jäit, verkossa tai sovelluksessa.
- Kurssit
- 12
- Oppitunnit
- 48
Usein kysytyt kysymykset
Onko oppitunti ”Supervisors-prosessit ja sovellusrakenne” ilmainen?
Kyllä – oppitunnin ”Supervisors-prosessit ja sovellusrakenne” koko tekstin voi lukea täällä verkossa ilmaiseksi. Jos haluat harjoitella interaktiivisesti sisäänrakennetulla koodieditorilla ja ympäri vuorokauden käytettävissä olevan tekoälytuutorin avulla sekä avata koko Elixir ja Phoenix: skaalautuva backend-kehitys-kurssin, päivitä CoddyKit PROhon. Elixir ja Phoenix: skaalautuva backend-kehitys-kurssilla on yhteensä 4 oppituntia.
Mitä opin oppitunnilla ”Supervisors-prosessit ja sovellusrakenne”?
Suunnitelkaa vikasietoisia sovelluksia supervisoreiden avulla valvomalla ja käynnistämällä prosesseja uudelleen. Harjoittelet Elixir ja Phoenix: skaalautuva backend-kehitys-aihetta koodilla, jonka suoritat suoraan selaimessa. Ympäri vuorokauden käytettävissä oleva tekoälytuutori vastaa kysymyksiisi oppitunnin aikana.
Tarvitsenko kokemusta aloittaakseni Elixir ja Phoenix: skaalautuva backend-kehitys-opiskelun?
Aiempi kokemus ei ole tarpeen. CoddyKitin Elixir ja Phoenix: skaalautuva backend-kehitys-oppimispolku sopii vasta-alkajista edistyneisiin, joten voit aloittaa tästä tai alusta ja edetä omaan tahtiisi. Tämä on oppitunti 3/4.
Kuinka kauan ”Supervisors-prosessit ja sovellusrakenne”-oppitunnin suorittaminen kestää?
Useimmat CoddyKitin oppitunnit kestävät noin 5–10 minuuttia. Jokainen oppitunti on lyhyt ja interaktiivinen, joten edistyt tasaisesti ja voit jatkaa siitä, mihin jäit – sekä verkossa että sovelluksessa.
Voinko kirjoittaa ja suorittaa koodia tällä Elixir ja Phoenix: skaalautuva backend-kehitys-oppitunnilla?
Kyllä. Jokainen Elixir ja Phoenix: skaalautuva backend-kehitys-oppitunti sisältää sisäänrakennetun koodieditorin, joten voit kirjoittaa ja suorittaa oikeaa koodia suoraan selaimessa ja saada välitöntä palautetta tekoälyltä – paikallista asennusta ei tarvita.
Kaikki tämän kurssin oppitunnit
- Elixirin prosessit ja viestinvälitys
- GenServer-käyttäytymisen toteuttaminen
- Supervisors-prosessit ja sovellusrakenne
- Samanaikainen työ Task- ja Agent-abstraktioilla