Undantagshantering är en bra övning för alla mjukvaruutvecklingsmetoder. Oavsett om det gäller testbaserad utveckling, smidiga sprints eller en hackingsession med bara en bra gammal todo-lista, kan vi alla dra nytta av att våra baser är täckta med ett robust tillvägagångssätt vid felhantering.
Det är av största vikt att se till att fel tas hand om, samtidigt som det är estetiskt tilltalande och naturligtvis inte blir ett stort problem logiskt med kryptiska meddelanden för slutanvändaren att försöka få bort betydelsen från. Om du gör det är du verkligen på en bra väg att skapa en stabil, stabil och klibbig app som användarna trivs med och kommer att rekommendera starkt till andra.
Idealiskt för oss erbjuder Elixir omfattande undantagshantering via flera mekanismer som försök fånga
, kastar
, och den : fel, orsak
tupel.
För att visa ett fel, använd höja
i ditt interaktiva skal för att få en första smak:
iex> höja "Oh någotz!" ** (RuntimeError) Oh någotz!
Vi kan också lägga till en typ till så här:
iex> höj ArgumentError, meddelande: "error message here ..." ** (ArgumentError) felmeddelande här ...
Några av de sätt som fel behandlas i Elixir kan inte vara uppenbara vid första anblicken.
rom
, Vi kan skapa självständiga processer. Det betyder att ett misslyckande på en tråd inte skulle påverka någon annan process, om det inte fanns någon koppling på något sätt. Men som standard kommer allt att vara stabilt.spawn_link
makro. Detta är en dubbelriktad länk, vilket innebär att om en länkad process upphör, utlöses en utgångssignal.:vanligt
, vi vet att vi har ett problem. Och om vi fäller utgångssignalen med Process.flag (: trap_exit, true)
, Utgångssignalen skickas till processens brevlåda, där logiken kan placeras på hur man hanterar meddelandet och därigenom undviker en hård krasch.spawn_links
, men dessa är enriktade länkar, och vi kan skapa dem med Process.monitor
. Process.monitor
kommer att få felmeddelanden vid fel.För ett provfel, försök att lägga till ett tal till en atom och du kommer att få följande:
iex>: foo + 69 ** (ArithmeticError) dåligt argument i aritmetiskt uttryck: erlang. + (: foo, 69)
För att säkerställa att slutanvändaren inte blir felaktig kan vi använda försöket, fångst och räddningsmetoder som tillhandahålls av Elixir.
Först i vår verktygslåda för undantagshantering är prova / räddning
, som fångar fel som produceras genom att använda höja
så är det bäst lämpat för utvecklarfel eller exceptionella omständigheter som inmatningsfel.
prova / räddning
är liknande för användning till a försök fånga
block du kanske har sett på andra programmeringsspråk. Låt oss titta på ett exempel i åtgärd:
iex> försök ...> höja "misslyckas!" ...> rädda ...> e i RuntimeError -> IO.puts ("Error:" <> e.message) ...> slutfel: misslyckas! :ok
Här använder vi prova / räddning
blockera och ovannämnda höja
att fånga RuntimeError
.
Detta betyder ** (RuntimeError)
standardutgång av höja
visas inte och ersätts med en snyggare formaterad utgång från IO.puts
ring upp.
Som en bra metod måste du använda felmeddelandet för att ge användaren användbar produktutskrift på vanlig engelska, vilket hjälper dem med problemet. Vi tittar på det mer i nästa exempel.
En stor fördel med Elixir är att du kan fånga flera resultat i en av dessa prova / räddning
block. Titta på detta exempel:
försök gör opts |> Keyword.fetch! (: source_file) |> File.read! räddning e i KeyError -> IO.puts "saknas: source_file option" e i File.Error -> IO.puts "kan inte läsa källfilens slut
Här har vi fångat två fel i rädda
.
:källfilen
symbolen saknas. Som tidigare nämnts kan vi använda det här för att göra felmeddelanden som är lätt att förstå för slutanvändaren.
Denna kraftfulla och minimala syntaxanvändning av Elixir gör att du skriver flera kontroller som är mycket tillgängliga för oss för att kontrollera många möjliga misslyckanden, på ett snyggt och koncist sätt. Detta hjälper oss att se till att vi inte behöver skriva utarbetade villkor som gör långvariga skript som kan vara svåra att visualisera fullständigt och felsöka korrekt under senare utveckling eller för att en ny utvecklare ska gå med.
Som alltid när man arbetar i Elixir är KISS det bästa sättet att ta.
Det finns situationer när du behöver en särskild åtgärd som utförs efter försök / räddningsblocket, oavsett om det fanns något fel. För Java eller PHP-utvecklare kanske du tänker på prova / fångst / slutligen
eller Ruby s börja / räddning / säkerställa
.
Låt oss ta en titt på ett enkelt exempel på att använda efter
.
iex> försök ...> höja "Jag vill prata med chefen!" ...> rädda ...> e i RuntimeError -> IO.puts ("Ett fel inträffade:" <> e.message) ...> efter ...> IO.puts "Oavsett vad som händer uppstår jag alltid som en dålig öre." ...> slutet Ett fel inträffade: Jag vill prata med chefen! Oavsett vad som händer uppstår jag alltid som en dålig öre. :ok
Här ser du efter
används för att ständigt göra en meddelandeskärm (eller det kan vara en funktion som du vill kasta in där).
En mer vanlig praxis hittar du här används på är var filen öppnas, till exempel här:
: ok, file = File.open "would_defo_root.jpg" försök göra # Prova åtkomst till filen här efter # Se till att vi städa upp efteråt File.close (file) end
Så väl som höja
och försök fånga
metoder vi har skisserat tidigare, vi har också kasta och fånga makron.
Använda kasta
Metoden avslutar utförandet med ett specifikt värde som vi kan leta efter i vårt fånga
blockera och använd vidare som så:
iex> försök göra ...> för x <- 0… 10 do… > om x == 3 gör: kasta (x) ...> IO.puts (x) ...> slutet ...> fånga ...> x -> "Fångad: # x" ...> slut 0 1 2 "Fångad: 3"
Så här har vi förmågan att fånga
något vi kasta
inuti försöksblocket. I det här fallet är den villkorliga om x == 3
är utlösaren för vår göra: kasta (x)
.
Utgången från iterationen som produceras från for loop ger oss en klar förståelse av vad som har hänt programmatiskt. Inkrementellt har vi gått framåt och utförandet har blivit stoppat på fånga
.
På grund av denna funktionalitet kan det ibland vara svårt att visa var kasta
fånga
skulle implementeras i din app. En viktig plats skulle vara att använda ett bibliotek där API: n inte har tillräcklig funktionalitet för alla resultat som presenteras för användaren, och en fångst skulle räcka för att snabbt navigera kring problemet, snarare än att behöva utveckla mycket mer inom biblioteket för att hantera Frågan och returnera på lämpligt sätt för den.
Slutligen har vi i vår Elixir felhanteringsarsenal den utgång
. Avslutande sker inte genom presentbutiken, men uttryckligen när en process dör.
Utgångar signaleras så här:
iex> spawn_link fn -> exit ("du är klar son!") slut ** (EXIT från #PID<0.101.0>) "du är klar son!"
Utgångssignaler utlöses av processer av en av följande tre skäl:
exit (0)
i C. Utgångsskälen för denna typ av utgång är atomen :vanligt
.prova / fångst / räddning
blockera eller kasta / fånga
att hantera det.:döda
, vilket tvingar mottagningsprocessen att avslutas.Vid en viss uppdateringstidpunkt på kasta
, utgång
eller fel
, ringer till System.stacktrace
kommer att returnera den senaste händelsen i den aktuella processen.
Stackspåret kan formateras en hel del, men detta kan komma att ändras i nyare versioner av Elixir. För mer information om detta, se den manuella sidan.
För att returnera stapelspåret för den aktuella processen kan du använda följande:
Process.info (self (),: current_stacktrace)
Ja, Elixir kan också göra det. Naturligtvis har du alltid de inbyggda typerna som RuntimeError
till ditt förfogande. Men skulle det inte vara trevligt om du kunde gå ett steg längre?
Att skapa din egen anpassade feltyp är lätt med hjälp av defexception
makro, som bekvämt kommer att acceptera :meddelande
alternativ, för att ställa in ett standardfelmeddelande som så:
defmodule MyError gör defexception meddelande: "ditt anpassade fel har inträffat" slutet
Så här använder du den i din kod:
iex> försök ...> upprepa MyError ...> rädda ...> e i MyError -> e ...> slut% MyError message: "din anpassade fel har uppstått"
Felhantering i ett metaprogrammeringsspråk som Elixir har en hel massa potentiella konsekvenser för hur vi utformar våra applikationer och gör dem robusta nog för en strikt basning av produktionsmiljön.
Vi kan se till att slutanvändaren alltid lämnas med en ledtråd - ett enkelt och lättförståeligt styrmeddelande som inte kommer att göra deras uppgift svår, utan snarare den inversa. Felmeddelanden måste alltidskrivs på vanlig engelska och ge mycket information. Kryptiska felkoder och variabla namn är inte bra för de genomsnittliga användarna, och kan även förvirra utvecklare!
Vidare kan du övervaka de undantag som höjts i din Elixir-applikation och konfigurera specifik loggning för vissa problemfel, så att du kan analysera och planera din åtgärd, eller du kan titta på att använda en lösning utan hylla.
Förbättra noggrannheten i vårt felsökningsarbete och möjliggöra övervakning av din apps stabilitet med dessa tredjepartstjänster tillgängliga för Elixir:
Vidare kan du önska att ytterligare utöka felsökningsfunktionerna för din app och göra din kod lättare att läsa. För detta rekommenderar jag att du kolla in det här projektet för elegant felhantering på GitHub.
!