op welk punt exception afhandelen?

Overzicht Reageren

Sponsored by: Vacatures door Monsterboard

Pagina: 1 2 3 volgende »

Ozzie PHP

Ozzie PHP

19/11/2013 02:57:47
Quote Anchor link
Fictieve situatie:
Stel je hebt een kernel. De kernel geeft de configurator opdracht om een paar instellingen te configureren. De configurator geeft vervolgens de cacher opdracht om deze instellingen op te slaan. De cacher geeft het filesystem opdracht om de instellingen in een bestand op te slaan.

Schematisch:

Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
kernel => configurator => cacher => filesystem

Nu gaat er in het filesystem iets mis. Het bestand kan niet worden opgeslagen omdat de map-rechten verkeerd zijn ingesteld. Het filesystem gooit een exception. Deze wordt opgevangen door de cacher. Deze gooit ook een exception met als previous exception de filesystem exception. De configurator vangt de cacher exception op.

En nu? Ik vraag me af wat er nu moet gebeuren. Ik denk niet dat je het probleem van de verkeerde bestandsrechten via de code kunt oplossen, maar je zult wel moeten loggen dat er iets misgaat. Maar op welk punt doe je dat?

Situatie A)
De configurator vangt de cacher exception op en logt deze.

OF

Situatie B)
De configurator gooit ook weer een exception en deze exception wordt in de kernel opgevangen en vervolgens gelogd.

Dus situatie A)
- filesystem gooit filesystem exception
- cacher vangt filesystem exception en gooit cacher exception met de filesystem exception als previous exception
- configurator vangt de cacher exception en logt deze

of situatie B)
- filesystem gooit filesystem exception
- cacher vangt filesystem exception en gooit cacher exception met de filesystem exception als previous exception
- configurator vangt de cacher exception en gooit een configurator exception met de cacher exception als previous exception
- kernel vangt de configurator exception en logt deze

Kiezen jullie voor situatie A of B en waarom?

Ik heb zelf een lichte voorkeur voor A, omdat het configureren op zich wel goed gaat. Het cachen gaat fout, en de opdracht voor het cachen wordt in de configurator gegeven. Je zou dan kunnen zeggen dat je ook vanuit de configurator de fout moet loggen. Maar ga je het "breder" trekken, dan zou je kunnen zeggen dat er ergens tijdens het configureren iets is fout gegaan, en dat je om die reden een configurator exception gooit. Wat is wijs?
Gewijzigd op 19/11/2013 03:03:13 door Ozzie PHP
 
PHP hulp

PHP hulp

08/02/2023 14:55:10
 
Wouter J

Wouter J

19/11/2013 07:49:52
Quote Anchor link
Er is niks tijdens het comfigureren misgegaan. Alleen tijdens het opslaan. Het is een fout waar je programma gewoon om heen kan werken en dus is het nutteloos om je hele applicatie plat te gooien.
 
Ward van der Put
Moderator

Ward van der Put

19/11/2013 10:55:09
Quote Anchor link
Wouter J op 19/11/2013 07:49:52:
Er is niks tijdens het comfigureren misgegaan. Alleen tijdens het opslaan. Het is een fout waar je programma gewoon om heen kan werken en dus is het nutteloos om je hele applicatie plat te gooien.

Inderdaad, bijvoorbeeld een throw new FileSystem\Exception('Insufficient disk space') heeft voor de ene toepassing andere gevolgen dan voor de andere. Dat los je op in een try/catch.

Verder zou ik het loggen van exceptions wat meer loskoppelen van de exception handling. In je voorbeelden log je de FileSystem-exception pas een paar klassen dieper. Vergeet je dat of log je te weinig, dan gaat ware aard van de fout aan je voorbij. Achter de Cacher-fout gaat een FileSystem-probleem schuil; dát wil je kunnen terugvinden. Bovendien kan hetzelfde FileSystem-probleem elders andere problemen veroorzaken, bijvoorbeeld bij het archiveren van e-mail of het uploaden van afbeeldingen. Op systeemniveau wil je weten welke systeemonderdeel faalt.

Als je "verantwoordelijkheden" nog ruimer neemt, belanden andere soorten fouten in een organisatie op een ander bureau. Dat heeft dus mogelijk consequenties voor hoe je het gebruik van de logs inricht.
 
Ozzie PHP

Ozzie PHP

19/11/2013 13:50:33
Quote Anchor link
Interessante reacties.

>> Er is niks tijdens het comfigureren misgegaan. Alleen tijdens het opslaan. Het is een fout waar je programma gewoon om heen kan werken en dus is het nutteloos om je hele applicatie plat te gooien.

Oke, dat is ook mijn gedachtengang.

>> Verder zou ik het loggen van exceptions wat meer loskoppelen van de exception handling. In je voorbeelden log je de FileSystem-exception pas een paar klassen dieper. Vergeet je dat of log je te weinig, dan gaat ware aard van de fout aan je voorbij.

Ward, dit vind ik een hele interessante opmerking. Hoe ik het in eerdere gesprekken heb begrepen, zou het in dit geval juist logisch zijn om de cacher exception te loggen. Je zegt dan WAT er is misgegaan, namelijk "het cachen is mislukt". Als het goed is bevat de cacher exception dan weer een previous exception waarin vermeld staat dat er een fout is opgetreden in het filesystem.

De totale melding wordt dus: Let op, er is iets fout gegaan met cachen -> Er is iets niet goed gegaan met het opslaan van bestand foo.

Ik dacht dat dit de bedoeling was?
 
Wouter J

Wouter J

19/11/2013 13:51:45
Quote Anchor link
Nee, dat is voor debuggen. (dus tonen op scherm) Voor het loggen zou ik ook de fout loggen voordat je de exception gooit (wanneer je de exception belangrijk genoeg vind om te loggen).
 
Ozzie PHP

Ozzie PHP

19/11/2013 14:13:51
Quote Anchor link
Wouter... nu ben ik even de weg kwijt.

Ik dacht dat het als volgt werkte, maar blijkbaar zit ik er nu naast:

Filesystem gooit een exception. Aan die exception geef ik een $message mee "filesystem could not save file blabla". De cacher vangt deze exception op en gooit een cacher exception met als $message "cacher could not cache file blabla". De cacher exception krijgt als previous exception de filesystem exception mee.

Vervolgens wordt de cacher exception opgevangen door de configurator. Dit is dus het punt waarop het eigenlijk fout is gegaan. Namelijk de configurator wil iets cachen en dat is niet gelukt. Ik had dan ook het idee om op dit punt, waar de fout optreedt, te bepalen wat ik ermee ga doen. In dit geval dus loggen. In de log komt dan zoiets te staan: 20131109 14:12 configurator could not cache file blabla. cacher could not cache file blabla. filesystem could not save file blabla

Aan jullie laatste reacties te horen, klopt dit niet helemaal. Maar hoe hoort het dan wel?
Gewijzigd op 19/11/2013 14:14:14 door Ozzie PHP
 
Ward van der Put
Moderator

Ward van der Put

19/11/2013 14:40:37
Quote Anchor link
Daarom zei ik al: loggen is niet hetzelfde als exception handling. En exception handling is niet hetzelfde als error handling.

Stel, je hebt A -> B -> C voor een operatie. In A treedt een probleem op, maar B weet het te omzeilen. Dan is er wat C betreft geen probleem meer.

Voorbeeldje. Met een cURL-verzoek (mijn B) haal ik data op bij een externe server (A). Die data veranderen echter niet vaak. Mislukt het cURL-verzoek, meestal doordat de externe service er uit ligt, dan gebruik ik oudere data uit een cache. Applicaties die de data vervolgens gebruiken (C) hoeven dat niet te weten.

Heel letterlijk dus: deze exception is een uitzondering, niet per se een fout en liever helemaal geen fatale fout.
 
Ozzie PHP

Ozzie PHP

19/11/2013 14:46:43
Quote Anchor link
Ward, ik snap jouw voorbeeld volkomen. Echter, ik neem aan dat je wel ergens wilt loggen dat het cURL verzoek mislukt is toch? Want stel dat het verzoek continu blijft mislukken, en jij logt dat nergens, dan heb jij dus niks in de gaten en zal je data steeds verder verouderen.

In mijn voorbeeld met het cachen, is het op zich niet zo erg dat het cachen mislukt. De applicatie kan gewoon doorgaan, alleen de gegevens moeten telkens "on the fly" geconfigureerd worden in plaats van dat ze uit het cache-bestand komen. Geen onoverkomelijk probleem weliswaar, maar ik wil er wel (via een logbericht) van op de hoogte worden gebracht. Ik dacht dat dus te doen op de manier zoals ik in mijn bericht hierboven precies heb omschreven. Ik ben benieuwd wat daar dan niet juist aan is, of wat er beter kan.
 
Wouter J

Wouter J

19/11/2013 14:55:56
Quote Anchor link
Door het loggen in de FileSystem te doen heb je hetzelfde effect.
 
Ward van der Put
Moderator

Ward van der Put

19/11/2013 15:07:24
Quote Anchor link
Dan heb je dus een throw in het FileSystem en een catch in de Cacher. Kan de Cacher de exception afvangen, dan is het probleem opgelost. Kan de Cacher dat niet, dan doe je opnieuw een throw. Je kunt eventueel nog in een catch "re-throwen" met throw $e als je wilt dat de FileSystem-exception boven komt.

Loggen zou ik in beide klassen doen.

Je kunt overigens altijd wel loggen, alleen wil je niet van elke log een e-mailbericht maken. Ik heb je geloof ik wel eens verteld dat ik een 403 logde. Dat wil je niet: dan komen alle activiteiten van een firewall bovendrijven.
Gewijzigd op 19/11/2013 15:07:55 door Ward van der Put
 
Ozzie PHP

Ozzie PHP

19/11/2013 15:33:09
Quote Anchor link
>> Door het loggen in de FileSystem te doen heb je hetzelfde effect.

Oké, maar als ik me niet vergis zeiden jullie eerder dat het afhandelen van een exception + het loggen/e-mailen pas gebeurt op de plek waar je de exception opvangt. Want in het ene geval wil je iets wel loggen, en in het andere geval niet. Dat lijkt elkaar nu tegen te spreken.

Stel ik wil een bestand cachen, maar het filesystem kan het bestand niet opslaan omdat de map-rechten van de cache-directory verkeerd zijn ingesteld. Op zich best vervelend, maar de applicatie kan gewoon doorwerken. Echter, als alle klanten ineens geen facturen kunnen opslaan, is het probleem van een heel andere orde en moet er andere actie worden ondernomen. Niet het filesystem bepaalt dan wat er moet gebeuren, maar de aanroepende class(es). Tenminste, zo heb ik het eerder van jullie begrepen.

>> Dan heb je dus een throw in het FileSystem en een catch in de Cacher. Kan de Cacher de exception afvangen, dan is het probleem opgelost. Kan de Cacher dat niet, dan doe je opnieuw een throw. Je kunt eventueel nog in een catch "re-throwen" met throw $e als je wilt dat de FileSystem-exception boven komt.

De cacher kan het probleem niet oplossen en zal dus een exception gooien. Die vang ik dan op in de configurator. In feite kan deze het probleem ook niet oplossen, maar zal wel de exception loggen, zodat ik zelf in actie kan komen om te kijken wat er aan de hand is en het probleem op te lossen.

Ward van der Put op 19/11/2013 10:55:09:
Inderdaad, bijvoorbeeld een throw new FileSystem\Exception('Insufficient disk space') heeft voor de ene toepassing andere gevolgen dan voor de andere. Dat los je op in een try/catch.

Hoe kun je trouwens vaststellen of je schijf vol is?
 
Ward van der Put
Moderator

Ward van der Put

19/11/2013 16:35:20
Quote Anchor link
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
<?php
$bytes_available
= disk_free_space('/');
?>


Om bij het voorbeeld te blijven: als je nog 5 MB over hebt, kan je nog heel wat zaken cachen, maar gaat het opslaan van een PDF van 10 MB niet lukken. Met andere woorden, dezelfde situatie eindigt niet altijd in dezelfde exception.

Je zou bijvoorbeeld exceptions van verschillende niveaus kunnen onderscheiden. Je krijgt dan als het ware een matrix met soorten exception (FileSystemException) en de ernst van de situatie (fatal FileSystemException, recoverable FileSystemException, enzovoort). De PSR-3 Logger Interface kent een leuk rijtje niveaus, tot en met de "emergency" voor "system is unusable".
 
Wouter J

Wouter J

19/11/2013 17:13:33
Quote Anchor link
Ozzie, merk op dat ik heel veel acties zou loggen. Bij mij zou de FileSystem class altijd loggen wanneer een bestand wordt opgeslagen/bewerkt. Wanneer dit dus niet slaagt zou dit ook gelogd worden.
Als het niet slagen uit eindelijk tot een fout leid die gelogd moet worden (merk op, een fout geen exception) dan zal het ook gelogd worden.

Dus je krijgt dan in je log file zeg maar:
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
[2013-11-19 15:08:30] core.DEBUG: FileSystem - updated file "cache019dy97eqr.inc"
[2013-11-19 15:18:34] core.DEBUG: Filesystem - could not update file "cache019dy97eqr.inc": "Insufficient disk space"
[2013-11-19 15:18:34] core.ERROR: Cacher - could not cache routes


Edit:
Merk op 2: De DEBUG logs zullen alleen in dev. omgeving worden gelogd. In prod. omgeving zou ik dan werken met een finger-crossed handler, waardoor deze pas worden gelogd wanneer de cacher een error logt.
Gewijzigd op 19/11/2013 17:16:04 door Wouter J
 
Ozzie PHP

Ozzie PHP

19/11/2013 17:18:29
Quote Anchor link
>> Om bij het voorbeeld te blijven: als je nog 5 MB over hebt, kan je nog heel wat zaken cachen, maar gaat het opslaan van een PDF van 10 MB niet lukken. Met andere woorden, dezelfde situatie eindigt niet altijd in dezelfde exception.

Oké, ik begrijp je. Als je dat dan terugbrengt naar mijn geschetste situatie, dan zou de cacher dus geen exception gooien, maar de class die de pdf van 10mb opslaat wel. Dat is dan in feite toch prima?

@Wouter: ah oké. Grappig dat je alles logt. Waarom doe je dat? Dingen die fout gaan begrijp ik, maar waarom log je ook zaken die goed gaan?

Toevoeging op 19/11/2013 17:20:06:

P.S.

@Ward... dank voor de disk_free_space funtie, maar hoe bepaal je dan in de praktijk dat het opslaan is mislukt vanwege te weinig schijfruimte?
 
Wouter J

Wouter J

19/11/2013 17:22:39
Quote Anchor link
> @Wouter: ah oké. Grappig dat je alles logt. Waarom doe je dat? Dingen die fout gaan begrijp ik, maar waarom log je ook zaken die goed gaan?

Helpt je erg bij het debuggen. Dan weet je tot hoever je applicatie nog goed ging en je kan eventueel al zien wat er verkeerd gaat (bijv. verkeerde bestand wordt gecached, etc.). Zoals ik in mijn edit al zei (die je mogelijk niet had gelezen) worden deze DEBUG dingen normaal gesproken niet gelogd wanneer alles goed gaat in de prod. omgeving.
 
Ozzie PHP

Ozzie PHP

19/11/2013 17:26:56
Quote Anchor link
Ah oké thanks, ik had je edit inderdaad niet gezien.

Kunnen jullie aub nog even reageren op mijn vraag hierboven... http://www.phphulp.nl/php/forum/topic/op-welk-punt-exception-afhandelen/93003/#666355

Klopt het nu wat ik doe, of niet? Het lijkt me namelijk wel een handige manier.
 
Ward van der Put
Moderator

Ward van der Put

19/11/2013 17:41:14
Quote Anchor link
Ik zou meer loggen. Maar verder heb ik er weinig op aan te merken.

Je kunt in een multi-processing omgeving namelijk zoiets verwachten:

1. Applicatie X vraagt via een if aan FileSystem of er genoeg ruimte is.
2. FileSystem antwoordt met (bool) ja of (int) 10 MB.
3. Applicatie Y knalt een upload van 5 MB op dezelfde schijf.
4. Applicatie X heeft nu misschien een probleem...

Als je logt zoals Wouter aangeeft, kun je dit terugvinden: oh het was onschuldig toeval, want er kwam net een bestand van 5 MB binnen. Gebeurt een keer per halfjaar, laat maar overwaaien.

Lees die PSR-3 verder even: daarin worden concrete noodgevallen van het type "stuur nu acuut een sms naar Ozzie" uitgewerkt. Bijna letterlijk :)
 
Ozzie PHP

Ozzie PHP

19/11/2013 17:52:48
Quote Anchor link
Ik zal het vanavond eens wat beter lezen.

Kom ik wel gelijk bij een volgende vraag ...

>> 1. Applicatie X vraagt via een if aan FileSystem of er genoeg ruimte is.

Doe je dit altijd als je iets opslaat? Vragen of er genoeg ruimte is? (en zo ja, hoe doe je dat.. hoe weet je of er genoeg ruimte is?) Ik doe dat nu namelijk (nog) niet, maar ik throw dus gewoon een error als het misgaat.

Ik denk dat je 2 dingen kunt doen. Direct opslaan, en als het misgaat throw je een exception. Of je controleert altijd eerst of er genoeg ruimte is... en zo niet, dan gooi je alsnog een exception. Maar feitelijk is dat toch dubbelop? Omdat file_put_contents dat neem ik aan zelf ook al zal doen (kijken of er genoeg ruimte is)? En zo niet dan returnt ie false en kun je een exception gooien.
 
Wouter J

Wouter J

19/11/2013 17:59:03
Quote Anchor link
>> en kun je een exception gooien.

En dan weet je totaal niet wat er nou precies mis ging, alleen dat het mis ging...
 
Ward van der Put
Moderator

Ward van der Put

19/11/2013 18:00:35
Quote Anchor link
Het kan beide en de variant die het op hoop van zegen probeert noemen we vaak "silent".

Maar je hebt wel een punt. Een superstabiel systeem zal vanwege allerlei "checks and balances" (inclusief extra exceptions) nooit supersnel zijn.

Ik zou in dit geval dus niet of/of maar en/en doen. 5 kilobyte kun je naar alle waarschijnlijkheid wel silent kwijt, maar 50 MB gaan we toch eerst even controleren.
 
Ozzie PHP

Ozzie PHP

19/11/2013 18:06:42
Quote Anchor link
>> En dan weet je totaal niet wat er nou precies mis ging, alleen dat het mis ging...

Ja, je hebt een punt. Maar hoe erg is dat? Als ik via mail een waarschuwing krijg "Filesystem could not save file blabla" dan weet ik toch genoeg? Dan is of de schijf vol, of de map-rechten kloppen niet. Of zie ik dat verkeerd?

>> Ik zou in dit geval dus niet of/of maar en/en doen. 5 kilobyte kun je naar alle waarschijnlijkheid wel silent kwijt, maar 50 MB gaan we toch eerst even controleren.

Oké, maar hoe weet ik hoeveel data het bestand dat moet worden opgeslagen in beslag gaat nemen? Dus stel we hebben data en die slaan we op:

$filesystem->save($data, $file);

Hoe weet je nu dan op voorhand hoe groot dat bestand gaat worden?
 

Pagina: 1 2 3 volgende »



Overzicht Reageren

 
 

Om de gebruiksvriendelijkheid van onze website en diensten te optimaliseren maken wij gebruik van cookies. Deze cookies gebruiken wij voor functionaliteiten, analytische gegevens en marketing doeleinden. U vindt meer informatie in onze privacy statement.