Thread: Error Handling

    #1
  1. No Profile Picture
    Contributing User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Dec 2016
    Location
    Lakewood, WA
    Posts
    70
    Rep Power
    17

    Error Handling


    What is the popular thinking on building some unified coherent error handling for a database heavy application? I'm contemplating (where it is appropriate) using a lot of try/catch to funnel things to an error handling class. I'm thinking that spreading it out over the several dozens of files will lead to general wonkiness and difficulty in maintaining a well thought out error handling scheme that also logs... Is this the right direction?
    Last edited by Arty Zifferelli; February 28th, 2017 at 07:50 PM.
  2. #2
  3. No Profile Picture
    Contributing User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Oct 2015
    Posts
    50
    Rep Power
    2
    Languages like Erlang and related ecosystems follow the "fail hard" philosophy, and it's actually very useful. Exceptions and errors should propagate up as much as possible.

    When using databases, this means use transactions, as you don't want your application to become unintentionally stateful, and failures should should rollback
    Last edited by oakleaf; February 28th, 2017 at 08:06 PM.
  4. #3
  5. Confusing Moderator
    Devshed Supreme Being (6500+ posts)

    Join Date
    Mar 2007
    Location
    Washington, USA
    Posts
    15,919
    Rep Power
    9570
    Technically, it depends. Are you using errors/warnings or exceptions? For the former a global error handler is probably fine, but for the latter you do need to care about catching exceptions because uncaught exceptions will kill the request.

    Oh. Forgot to mention: "both" is an even better answer.

    A general logging scheme is where you should be looking, rather than dealing specifically with errors. Errors are about using logging to record the fact that they happened (and then recovering as gracefully as possible). Logging is the primary concern, as having that in place makes the rest easier. For it you should have a central place in code to log something, such as a function or method call, so it's easy to do so from code and thus easy to alter what logging entails.
    For example, logging in my own code uses several functions named like "debug" or "warn" which hand off to a single logger class that decides what to do based on the severity and the (global) logging configuration. I can sprinkle stuff like
    PHP Code:
    info(["Logging in user #%d %s"$user_id$user_email]); // message gets sprintf()ed 
    PHP Code:
    } catch (SomeParticularException $e) {
        
    error($e);
        
    /* react appropriately */

    PHP Code:
    debug(["Loading class %s from file %s"$class$path]); 
    wherever without having to think too much about it.
  6. #4
  7. No Profile Picture
    Contributing User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Oct 2015
    Posts
    50
    Rep Power
    2
    For specifics, I set my exception handler to report all non-excluded (I don't want to report 404s, for instance) exceptions to a reporting service such as BugSnag.. I also log them to a log file.

    If I have to do something specific with errors in a method, I always re-throw it because I want to move responsibility up from the method to its caller, to its caller, etc etc.

    But in general, you should never let things handle their own errors. Not only does it do what it was made to do, but now it has to deal with its own failures.

    For instance, let's say I'm downloading orders from an external source and I get to an item on that order that is invalid (invalid quantity, product doesn't exist, whatevs). I throw an exception in the order item repository, then it goes to the order repository, which sees that an exception occured creating items, and does what it needs to do, then rethrows it up to the command calling the order repository, which handles it and rethrows it and it's finally caught by the error logger.
    Last edited by oakleaf; March 1st, 2017 at 06:05 PM.
  8. #5
  9. Confusing Moderator
    Devshed Supreme Being (6500+ posts)

    Join Date
    Mar 2007
    Location
    Washington, USA
    Posts
    15,919
    Rep Power
    9570
    Originally Posted by oakleaf
    But in general, you should never let things handle their own errors. Not only does it do what it was made to do, but now it has to deal with its own failures.
    I would rephrase that as something like "Only handle errors (or exceptions) in the places that know what to do to handle the errors". Some things will create errors and should also be the ones to deal with the consequences. And sometimes it's good to wrap a caught exception in another exception and throw that one instead.

    I'd continue with the order downloading example but I don't really follow what it's about...

    Database stuff. Say I'm running a query and I, the developer, made a bug in some search page I made where the SQL is invalid under certain conditions. Also say that I'm using a database adapter, and it uses PDO behind the scenes.
    The bad query runs. PDO will throw a PDOException, but my code shouldn't need to care about whether we have PDO or mysqli or whatever. So the adapter does
    PHP Code:
    } catch (PDOException $e) {
        
    LoggingUtility::logException($e, ["query" => $query]); // log the exception with metadata
        
    throw new DatabaseQueryExecutionException($e); 
    There are two possibilities for what my code does next: react to the exception or let it go up the call stack. Which comes down to whether it's the right place to deal with database errors. There are two questions to answer:
    1. Do I know what to do with a database query execution failure?
    2. Does calling code, either the immediate parent or some ancestor in the call stack, know what to do with a database query execution failure?

    For my search page the answers are:
    1. Yes, I know what to do. My search page is issuing database queries directly so it should also be capable of handling database query failure. Such a problem severely impacts what the user will receive as a response (they expect search results but I can't provide them) and I probably also have the ability to alter the response (by showing an error message or whatever). This is a good place to handle the exception.
    2. No, calling code shouldn't know. The failure is in the ability for the search page to perform its expected action, however the page can instead react with a different action (ie, show an error) and cleanly exit having performed its requirement of "display the result of executing a search".

    Alternatively,
    1. Yes, I know what to do. As above it should handle a database error, however in this variation the search page decides that it is not capable of performing its duty of showing search results. The database problem has become a grander problem of being unable to show a page to the user, and it does not know how to recover from that. This is a case where it should wrap the exception in another which calling code can reasonably expect (eg, "PageExecutionException") and throw it up the stack.
    2. Yes, calling code should know how to react to the new PageExecutionException that was just thrown. The search page was invoked using some process that runs "pages", therefore it should be able to react to a situation where the page could not execute. For example, the parent may decide to abort execution of the correct page and instead execute the 500 error page.


    Anyway, I'm rambling.

    Cardinal rule of exceptions: don't catch them unless you know specifically what to do with them. An empty catch { } block is 99.999% of the time an egregious sin. Anything else is debatable and probably varies with circumstances and application design.


    And to counter what I've said: don't wrap exceptions too deeply. This isn't Java. I'd show a screenshot of what I mean but I couldn't find one so you'll have to settle for one of Java's other problem.
    Last edited by requinix; March 1st, 2017 at 07:31 PM.

IMN logo majestic logo threadwatch logo seochat tools logo