16

I have an app that runs a long batch process where many exceptions could potentially be thrown. If a non-critical exception is thrown during one item in the batch, I want to simply log it and continue, so we can fix the problem later while letting the other batch items continue.

Some exceptions, such as OutOfMemoryException, are devastating to the app as a whole, and these I would like to rethrow so that they bubble up to global exception handler which will log the error and stop the app.

So my question is, is there a reasonbly short list of critical exceptions that I can rethrow in my lower exception handler while suppressing (after logging) everything else?

Thanks!

Edit: To elaborate a little, here is the basic structure of my program

foreach(var item in longItemList)
{
   try
   {
      bigDynamicDispatchMethod(item);
   }
   catch(Exception ex)
   {
      logException(ex);
   }
}

There are potentially a huge number of exceptions that could be thrown because this loop is pretty much at the top level of my app. 99% of the code in my project is behind the dispatch method. I do reasonable exception handling at lower levels, but bugs still work their way in and I don't want to stop other unrelated processes in the batch after an exception is thrown.

Trying to find which exceptions could be thrown everywhere else in my app seems like a daunting task, and it seemed to be that it would be simpler to get a blacklist of critical exceptions.

Is there a better way to structure my app to deal with this? I am open to suggestions.

nw.
  • 4,795
  • 8
  • 37
  • 42
  • possible duplicate of [Which types of exception not to catch?](http://stackoverflow.com/questions/5507836/which-types-of-exception-not-to-catch) – Hans Passant Aug 22 '11 at 19:55

6 Answers6

28

You don't need a list of 'bad' exceptions, you should treat everything as bad by default. Only catch what you can handle and recover from. CLR can notify you of unhandled exceptions so that you can log them appropriately. Swallowing everything but a black listed exceptions is not a proper way to fix your bugs. That would just mask them. Read this and this.

Do not exclude any special exceptions when catching for the purpose of transferring exceptions.

Instead of creating lists of special exceptions in your catch clauses, you should catch only those exceptions that you can legitimately handle. Exceptions that you cannot handle should not be treated as special cases in non-specific exception handlers. The following code example demonstrates incorrectly testing for special exceptions for the purposes of re-throwing them.

public class BadExceptionHandlingExample2 {
    public void DoWork() {
        // Do some work that might throw exceptions.
    }
    public void MethodWithBadHandler() {
        try {
            DoWork();
        } catch (Exception e) {
            if (e is StackOverflowException ||
                e is OutOfMemoryException)
                throw;
            // Handle the exception and
            // continue executing.
        }
    }
}

Few other rules:

Avoid handling errors by catching non-specific exceptions, such as System.Exception, System.SystemException, and so on, in application code. There are cases when handling errors in applications is acceptable, but such cases are rare.

An application should not handle exceptions that can result in an unexpected or exploitable state. If you cannot predict all possible causes of an exception and ensure that malicious code cannot exploit the resulting application state, you should allow the application to terminate instead of handling the exception.

Consider catching specific exceptions when you understand why it will be thrown in a given context.

You should catch only those exceptions that you can recover from. For example, a FileNotFoundException that results from an attempt to open a non-existent file can be handled by an application because it can communicate the problem to the user and allow the user to specify a different file name or create the file. A request to open a file that generates an ExecutionEngineException should not be handled because the underlying cause of the exception cannot be known with any degree of certainty, and the application cannot ensure that it is safe to continue executing.

Eric Lippert classifies all exceptions into 4 groups: Fatal, 'Boneheaded', Vexing, Exogenous. Following is my interpretation of Eric's advice:

  Exc. type | What to do                          | Example
------------|-------------------------------------|-------------------
Fatal       | nothing, let CLR handle it          | OutOfMemoryException
------------|-------------------------------------|-------------------
Boneheaded  | fix the bug that caused exception   | ArgumentNullException
------------|-------------------------------------|-------------------
Vexing      | fix the bug that caused exception   | FormatException from 
            | (by catching exception  because     | Guid constructor
            | the framework provides no other way | (fixed in .NET 4.0 
            | way of handling). Open MS Connect   | by Guid.TryParse)
            | issue.                              | 
------------|-------------------------------------|-------------------
Exogenous   | handle exception programmatically   | FileNotFoundException 

This is roughly equivalent to Microsoft's categorization: Usage, Program error and System failure. You can also use static analysis tools like FxCop to enforce some of these rules.

Community
  • 1
  • 1
Dmitry
  • 17,078
  • 2
  • 44
  • 70
  • 4
    You can handle vexing exceptions as well. They are vexatious because you *must* handle them in most situations. – Eric Lippert Aug 22 '11 at 22:48
  • @Eric: I've updated the answer with my interpretation of you article, hope I got it right. – Dmitry Aug 22 '11 at 23:25
  • So is there a list of fatal exceptions somewhere? I intend to fix all the exceptions that show up in my log, but seeing as there is no global state in my app, I don't see how a boneheaded or vexing exception in one of the batch items can affect any of the other batch items. I don't want my program to halt on this situation. Is there a better way to deal with this? – nw. Aug 23 '11 at 00:34
  • The best way to deal with this is to subscribe to AppDomain.UnhandledException, log, and start fixing bugs until your process stops crashing. I don't know of any official lists of 'fatal' exceptions. Apparently Microsoft.VisualStudio.S‌​hell assembly contains a method IsCriticalException but this may or may not be what you consider 'fatal': http://stackoverflow.com/questions/5507836/which-types-of-exception-not-to-catch/5508733#5508733 – Dmitry Aug 23 '11 at 03:22
  • I have un-"wikied" the question, take care in the future to avoid mass-editing, try to read through the entire post and edit more in one go, but you already know this :) – Lasse V. Karlsen Aug 23 '11 at 08:33
  • I'm not sure the answer to this is that clear cut. I got burned many times by buggy APIs (including some in the [.NET framework itself](https://codereview.stackexchange.com/q/139474/99069)) that would throw `ArgumentException` or leak COM exceptions that only happened once in a blue moon; most APIs I work with don't even tell you what exceptions will be thrown, or when, some docs don't even give you enough information to prevent an `ArgumentException`, some will throw `ArgumentException` in cases where the caller had no way of knowing the argument wasn't good... – jrh Jul 13 '18 at 13:51
  • ... from my experience classes that corrupt their state irrecoverably are rare in .NET (C++ is a different case entirely); sometimes they just crash the whole program with an `AccessViolationException`, then again there's some classes that will limp on when they are terminally ill and will do that forever instead of trying to build in some kind of recovery method for their broken internals (in some cases they could have, but chose not to, instead letting the caller deal with leaked implementation detail `Exception`s thrown at random from any / every property).... – jrh Jul 13 '18 at 13:58
  • ... hate to say it but after working with .NET for a while I start to wonder sometimes if this whole type system based exception methodology is flawed since it seems to put a huge burden on library writers (they have to be perfect and every class they call has to be perfect, and the documentation has to be perfect, otherwise the caller gets an unhandled exception that *they can't fix*, which I shouldn't catch, even though this one method isn't system critical at all and has no side effects). Might not be an easy answer for that though – jrh Jul 13 '18 at 14:03
11

Don't catch any exceptions you don't know how to handle safely.

Catching Exception is a particularly bad practice, the only one worse is a catch that doesn't specify any managed exception type (as it would catch non-managed exceptions as well).

Oded
  • 489,969
  • 99
  • 883
  • 1,009
  • .NET 2.0 will automatically wrap non-CLS compliant exceptions (i.e., any exception whose class doesn't inherit from Exception) as RuntimeWrappedException when presenting them to catch blocks in CLS-compliant code; so there's really no reason to use parameterless catch blocks at all. – Timothy Fries Aug 22 '11 at 19:27
  • I follow this advice in most cases, but this is somewhat of a special case. See edit. – nw. Aug 22 '11 at 19:32
1

A more proper design would be supported by the question: Which exceptions should I catch?

If you really need to catch any and all exceptions and still keep going, then you should be using both AppDomains and separate worker processes. Or change your host to ASP.NET or the task scheduler, which have already done all the hard work around process isolation and retries.

Stephen Cleary
  • 437,863
  • 77
  • 675
  • 810
1

Unless you apply HandleProcessCorruptedStateExceptions attribute to an exception handling function, all the 'shouldn't be handled by the user code' exceptions are already ignored you so you can handle anything other than process corrupting exceptions safely.

Teoman Soygul
  • 25,584
  • 6
  • 69
  • 80
1

I would refer to the advice from the following article.

.NET Framework design guidelines rules: Do Not Catch Exceptions That You Cannot Handle

http://www.codeproject.com/KB/cs/csmverrorhandling.aspx

Also from the referenced article:

You should never catch System.Exception or System.SystemException in a catch block

Thomas Langston
  • 3,743
  • 1
  • 25
  • 41
1

Catch errors that you expect your code to throw.. When ever you are using an API or a method see what exceptions it will throw and catch only those.. You shouldn't make a list f exceptions and always catch those..

  • Read from msdn google exception handling best practices
  • Never catch wit the non-specific exceptions like Exception
Baz1nga
  • 15,485
  • 3
  • 35
  • 61