C# Compare Exceptions - c#

I have a piece of code that sometimes throws an exception and sometimes doesn't. Depending on IO and network, different kinds of exception might be thrown. I have a wrapper for that code that shall retry the failing statement, say 10 times until it succeeds. If the exception does not go away after the 10th time, I rethrow it. Until now, I know what to do. Currently, I have something like this:
private void ExecuteStatement(Action statementToExecute)
{
while (true)
{
int exceptionCount = 0;
try
{
statementToExecute.Invoke();
// statement finished successfully
break;
}
catch (Exception e)
{
if (!IsFrameworkException(e))
throw; // rethrow as it isn't a framework exception
// we know now that it's a framework exception
exceptionCount++;
if (exceptionCount >= MaxRetriesOnFrameworkException)
throw;
}
}
}
The issue is the following: I want to reset the counter in case the exception changes (i. e. different type, different stacktrace, different message). I know how to compare them individually, but I want to know if there's a standard C# way of accomplishing this.
Edit: Here's the code of IsFrameworkException:
private bool IsFrameworkException(Exception e)
{
Exception rootCause = e.GetBaseException();
return rootCause.GetType() == typeof(WebException);
}

This is not specifically related to exception handling, but a simple way to keep counters by a specific key is to use a Tuple as the key (it implements equality by value out of the box).
Note that this doesn't reset the counter on key change, it justs keeps separate counters for each key:
readonly Dictionary<Tuple<Type, string, string>, int> _counters =
new Dictionary<Tuple<Type, string, string>, int>();
bool IsCountExceeded(Exception ex)
{
// create your key with whatever properties you consider to
// be "unique"
var key = Tuple.Create(ex.GetType(), ex.StackTrace, ex.Message);
// increase counter
int counter;
if (!_counters.TryGetValue(key, out counter))
{
counter = 1;
}
else
{
counter++;
}
_counters[key] = counter;
return counter > Max;
}
You can of course always make it more readable by creating your own class, which will implement Equals/GetHashCode properly.
I am also not sure that the stack trace can be considered as a unique property, and of course, catching and ignoring exceptions is usually a bad idea.

You should specify the exception type you want to catch. Place the catch blocks in order of most specific type to most generic type.
It is not clear if the exceptions all derive from FrameworkException or if you want to use Exception, the following assumes the former.
int exceptionCount = 0;
Type lastCaughtException = null;
while(true) {
try
{
statementToExecute.Invoke();
// statement finished successfully
break;
}
catch (WebException ex)
{
if(lastCaughtException == null || lastCaughtException != ex.GetType())
exceptionCount = 0;
else
exceptionCount++;
lastCaughtException = ex.GetType();
if (exceptionCount >= MaxRetriesOnFrameworkException)
throw;
}
catch (Exception) // if you do not want to log this you can completely omit this catch
{
throw; // rethrow as it isn't a framework exception
}
}
See also try-catch (C# Reference)

Related

How to handle exception in catch block?

I am trying to get the ideal way to handle exception. I googled & read that I should put try catch in the catch block as well to handle but what if any exception occurs in the nested block itself.
try
{
int a = 10;
int b = 0;
int c = a / b;
Console.WriteLine(c);
Console.ReadKey();
}
catch (Exception ex)
{
int a = 10; int b = 0;
int c = a / b;
Console.WriteLine(ex.Message.ToString());
Console.ReadKey();
}
finally
{
Console.WriteLine("Some Exception");
}
On googling I read that it should be decorated as below:
If exception occurs in Catch block itself then how to handle it in C#?
If exception occurs in Catch block itself then how to handle it in C#?
What happens if an exception occurs in Catch block in C#. Also what would be the caller result in that case
try
{
int a = 10;
int b = 0;
int c = a / b;
Console.WriteLine(c);
Console.ReadKey();
}
catch (Exception ex)
{
try
{
}
catch(Exception innerEx)
{
// What if exception here also occurs.
}
}
finally
{
Console.WriteLine("Some Exception");
}
If I do this way, then it will stuck in an infinite try-catch block.
I think there would be some better or the right way to handle this scenario.
I think there would be some better or the right way to handle this scenario.
No snark intended in this but simply, don't allow an exception to happen in the first place.
A try...catch is a language construct that ensures you handle an edge case or error you didn't mitigate and design for in the first place, hence why it's exceptional code.
In your code, you're simply throwing an error because of a division by 0, but in the real-world, you want to handle that and alert the user (or developer, or server, or whatever), and then handle the actual exceptional code, example:
static void PrintError()
{
Console.WriteLine("You must enter a valid number between {0} and {1}, excluding 0", int.MaxValue, int.MinValue);
}
static void Main(string[] args)
{
try {
int a = 10;
int b = 0;
PrintError(); // Tell user to enter valid numbers
while (b == 0) {
string user_input = Console.ReadLine();
if (int.TryParse(user_input, out b)) { // is it an actual number?
if (b == 0) { // no 0's remember user!??
PrintError();
} else {
// ok, everything checks out, so do what the system can actually handle without throwing an error
Console.WriteLine("a/b = {0}", (a / b));
}
} else {
PrintError();
}
}
} catch (Exception ex) {
Console.WriteLine("Something exceptional happened: {0}", ex);
}
}
This example could be simplified further, but it demonstrates there isn't an exception that could actually occur except something that is actually exceptional (i.e. out of memory error or some other system error).
In the event of larger code bases with multiple classes, the exception handler and finalizer would be where you could clean up resources acquired in other areas of the code, like closing a socket or file handle to ensure data is not lost.
In the event an error happens in the exception handler (something that can and does happen), you need to be aware of that and know what might happen in that case.
In the event of a C# application utilizing the .NET framework, an exception thrown within an exception will just cause the application to crash with the inner exception stack trace (versus the "outer" exception that's probably more relevant to the actual exception) if not handled.
There's plenty of "wrong" ways to handle exceptions (like not handling them at all), but there's not really a "right" way given the variable nature of exceptions.
Hope that can help.
First of all you need to know what does try,catch and finally works lets start:
Try: In this block we can write code which have the possibilities to throw some error (Better practice is to write code part in it.)
Catch: It is responsible to show error and what to do if error arises(Like in your code 10/0 throws error which can be handled in this section.)
Finally: Code written in this part will execute any how weather any error comes in or not.
Now for your query it would be better that you can use If...else in finally and code put in that part would be kept in try catch block.
For example:
bool flagCatch=false;
try
{
int a = 10;
int b = 0;
int c = a / b;
Console.WriteLine(c);
Console.ReadKey();
}
catch (Exception ex)
{
//Error handling
flagCatch=true;
Console.WriteLine(ex.Message.ToString());
Console.ReadKey();
}
finally
{
try
{
if(flagCatch)
{
//Code
}
else
{
//Code when error not comes
}
}
catch(Exception err)
{
//Error handling
}
}
I would go with the comment of Tieson T. . From my point of view it is an design issue.
I could also build an example with if statements -> if that goes wrong, I perform failure handling -> if the failure handling goes wrong, I perform failure handling, If the failure handling goes wrong ....
To make the code more readable, you can try to "hide" the try-catch blocks in method like:
static void PerformInTryCatch<T, TException>(Action<T> action, T obj) where TException : Exception
{
try
{
action(obj);
}
catch (TException exception)
{
// Perform some logging
}
}
Hope that helps.

Can I execute multiple catch blocks that correspond to one try block?

Consider I have a try block that contains 3 statements, and all of them cause Exceptions. I want all the 3 exceptions to be handled by their relevant catch blocks.. is it possible ?
something like this-->
class multicatch
{
public static void main(String[] args)
{
int[] c={1};
String s="this is a false integer";
try
{
int x=5/args.length;
c[10]=12;
int y=Integer.parseInt(s);
}
catch(ArithmeticException ae)
{
System.out.println("Cannot divide a number by zero.");
}
catch(ArrayIndexOutOfBoundsException abe)
{
System.out.println("This array index is not accessible.");
}
catch(NumberFormatException nfe)
{
System.out.println("Cannot parse a non-integer string.");
}
}
}
Is it possible to obtain the following output? -->>
Cannot divide a number by zero.
This array index is not accessible.
Cannot parse a non-integer string.
Is it possible to obtain the following output?
No, because only one of the exceptions will be thrown. Execution leaves the try block as soon as the exception is thrown, and assuming there's a matching catch block, it continues there. It doesn't go back into the try block, so you can't end up with a second exception.
See the Java tutorial for a general lesson in exception handling, and section 11.3 of the JLS for more details.
If you want to catch multiple exceptions, you have to split your code across multiple try/catch blocks.
A better approach is to validate your data and log errors without triggering Exceptions to do this.
To add to Jon's answer, while you won't catch multiple exceptions from a single try block, you can have multiple handlers handle a single exception.
try
{
try
{
throw new Exception("This is an exception.");
}
catch(Exception foo)
{
System.Console.WriteLine(foo.Message);
throw; // rethrows foo for the next handler.
}
}
catch(Exception bar)
{
System.Console.WriteLine("And again: " + bar.Message);
}
This produces the output:
This is an exception.
And again: This is an exception.
this is a REALY BAD PRACTICE, but you can do next (solve your problem using finally block):
private static void Main()
{
int[] c={1};
String s="this is a false integer";
try
{
int z = 0;
int x = 5/z;
}
catch (ArithmeticException exception)
{
Console.WriteLine(exception.GetType().ToString());
}
finally
{
try
{
c[10] = 12;
}
catch(IndexOutOfRangeException exception)
{
Console.WriteLine(exception.GetType().ToString());
}
finally
{
try
{
int y = int.Parse(s);
}
catch (FormatException exception)
{
Console.WriteLine(exception.GetType().ToString());
}
}
Console.ReadKey();
}
}
Showing all of the exceptions handling at once is impossible. The goal of each exception catch is to have a different handling for each Exception type and otherwise it's pointless to print them all together.
No ,
It will not execute all three catch statements. The TRY block checks for error and then the execution comes out of the TRY block. Then Suitable catch will be executed. In your case, The ArithmeticException is in the Top of the Exception Hierarchy. So it will Execute and then the program terminates.
If you give, Catch(Exception e) before ArithmeticException then Exception catch will be executed... Better read about the SystemException Hierarchies at MSDN

C# - Exception logging and return status

Modifying to make it clear:
I have a question on exception logging and graceful exit. This is in continuation with previous question. The code looks like:
string status = "0";
ClassA ObjA = new ClassA();
try
{
status = objA.Method1();
if (status != "-1")
{
status = objA.Method1();
}
}
catch (Exception Ex)
{
//Log Exception EX
}
Inside the Method1:
public string Method1()
{
string status = "0";
try
{
//Code
return "0";
}
catch (Exception Ex)
{
//Log Exception with details
return "-1"
}
}
I log the Exception in the calling method and return only a status to the caller.
Should I return the Exception to the calling method or is only a status sufficient. With a status of "-1", I know there was an Exception in the called method and details of that Exception were logged in a log file.
I think it is OK to do it like that if you have a lot of status codes, otherwise you could also just throw an exception and catch it in the method higher up.
Also maybe reconsider your return type. Looks like you could be using integers, think you are opening yourself up to errors using strings.
Don't use the status return value, it is not adding anything that is useful to you.
consider,
var a = new ClassA()
try
{
a.Mehtod1();
}
catch
{
try
{
a.Method1();
}
catch (Exception ex)
{
//Log without details;
}
}
class ClassA
{
void Method1()
{
try
{
//Code
}
catch (Exception ex)
{
//Log with details
throw;
}
}
}
This code achieves the same functionality but leaves the return code of the functions for something useful and non exceptional.
More generally, I suggest that you should have one catch all handler at the top level of your application that deals with logging, or at most one per public entry point. Other handlers should deal with specific exception types that they can actually "handle" (do something about.)
It all depends on the purpose and implementation of the code; sometimes it is better to allow exceptions to pass back to the caller - they should be used in exceptional cases.
If you do intend on using return codes, however, I would be more inclined to use enum's (though, again, it depends what the purpose of the code is). That way, it is easy for the caller to check against an available selection of return codes. Also, a comment on using integers or strings as error codes - it may not be very descriptive for a caller to know what the issue was. In this case, throwing an Exception or a specific type (containing the error message), or returning a pre-defined enum with a descriptive name, would be more meaningful to the caller.
From these short code snippets which does nothing it is very difficult to say what is best practice.
In general it is best to push exceptions to where they are handled best. If you are writing a framework for interfacing with some webservice the users of your framework will most likely not care about network exceptions etc. - they want return codes or, even better some framework specific exceptions that you include/code.
Hm - in your situation I'd rather do the following, but it really depends on the situation:
public string Method1()
{
string status = "0";
//Code - Exception may be thrown
return "0";
}
string status = "0";
ClassA ObjA = new ClassA();
try
{
status = objA.Method1();
}
Catch(Exception Ex)
{
//Log Exception EX
status = "-1;
}
EDIT
Sometimes it's hard to define values that indicate whether an error occurred in the method. You should keep Nullable types in mind. If you can find a suitable return value that indicates errors, it may also be ok to log the error within the method that caused the error and just react to the return value as you suggested.
By the way: In your code you're calling Method1 twice if the first call succeeded. I guess that is because it is a quick sample...
class MyException : Exception
{
public readonly int status;
public MyException(int status, string msg):base(msg)
{
this.status = status;
}
}
public string Method1()
{
throw new MyException(-1,"msg");
return "0";
}
SomeCode()
{
try
{
Method1();
}catch(MyException ex)
{
ex.status //here you get the status
}
}

Additional try statement in catch statement - code smell?

Situation:
My application need to process the first step in the business rules (the initial try-catch statement). If an certain error occurs when the process calls the helper method during the step, I need to switch to a second process in the catch statement. The back up process uses the same helper method. If an same error occurs during the second process, I need to stop the entire process and throw the exception.
Implementation:
I was going to insert another try-catch statement into the catch statement of the first try-catch statement.
//run initial process
try
{
//initial information used in helper method
string s1 = "value 1";
//call helper method
HelperMethod(s1);
}
catch(Exception e1)
{
//backup information if first process generates an exception in the helper method
string s2 = "value 2";
//try catch statement for second process.
try
{
HelperMethod(s2);
}
catch(Exception e2)
{
throw e2;
}
}
What would be the correct design pattern to avoid code smells in this implementation?
I caused some confusion and left out that when the first process fails and switches to the second process, it will send different information to the helper method. I have updated the scenario to reflect the entire process.
If the HelperMethod needs a second try, there is nothing directly wrong with this, but your code in the catch tries to do way too much, and it destroys the stacktrace from e2.
You only need:
try
{
//call helper method
HelperMethod();
}
catch(Exception e1)
{
// maybe log e1, it is getting lost here
HelperMethod();
}
I wouldn't say it is bad, although I'd almost certainly refactor the second block of code into a second method, so keep it comprehensible. And probably catch something more specific than Exception. A second try is sometimes necessary, especially for things like Dispose() implementations that might themselves throw (WCF, I'm looking at you).
The general idea putting a try-catch inside the catch of a parent try-catch doesn't seem like a code-smell to me. I can think of other legitimate reasons for doing this - for instance, when cleaning up an operation that failed where you do not want to ever throw another error (such as if the clean-up operation also fails). Your implementation, however, raises two questions for me: 1) Wim's comment, and 2) do you really want to entirely disregard why the operation originally failed (the e1 Exception)? Whether the second process succeeds or fails, your code does nothing with the original exception.
Generally speaking, this isn't a problem, and it isn't a code smell that I know of.
With that said, you may want to look at handling the error within your first helper method instead of just throwing it (and, thus, handling the call to the second helper method in there). That's only if it makes sense, but it is a possible change.
Yes, a more general pattern is have the basic method include an overload that accepts an int attempt parameter, and then conditionally call itself recursively.
private void MyMethod (parameterList)
{ MyMethod(ParameterList, 0)l }
private void MyMethod(ParameterList, int attempt)
{
try { HelperMethod(); }
catch(SomeSpecificException)
{
if (attempt < MAXATTEMPTS)
MyMethod(ParameterList, ++attempt);
else throw;
}
}
It shouldn't be that bad. Just document clearly why you're doing it, and most DEFINITELY try catching a more specific Exception type.
If you need some retry mechanism, which it looks like, you may want to explore different techniques, looping with delays etc.
It would be a little clearer if you called a different function in the catch so that a reader doesn't think you're just retrying the same function, as is, over again. If there's state happening that's not being shown in your example, you should document it carefully, at a minimum.
You also shouldn't throw e2; like that: you should simply throw; if you're going to work with the exception you caught at all. If not, you shouldn't try/catch.
Where you do not reference e1, you should simply catch (Exception) or better still catch (YourSpecificException)
If you're doing this to try and recover from some sort of transient error, then you need to be careful about how you implement this.
For example, in an environment where you're using SQL Server Mirroring, it's possible that the server you're connected to may stop being the master mid-connection.
In that scenario, it may be valid for your application to try and reconnect, and re-execute any statements on the new master - rather than sending an error back to the caller immediately.
You need to be careful to ensure that the methods you're calling don't have their own automatic retry mechanism, and that your callers are aware there is an automatic retry built into your method. Failing to ensure this can result in scenarios where you cause a flood of retry attempts, overloading shared resources (such as Database servers).
You should also ensure you're catching exceptions specific to the transient error you're trying to retry. So, in the example I gave, SqlException, and then examining to see if the error was that the SQL connection failed because the host was no longer the master.
If you need to retry more than once, consider placing an 'automatic backoff' retry delay - the first failure is retried immediately, the second after a delay of (say) 1 second, then doubled up to a maximum of (say) 90 seconds. This should help prevent overloading resources.
I would also suggest restructuring your method so that you don't have an inner-try/catch.
For example:
bool helper_success = false;
bool automatic_retry = false;
//run initial process
try
{
//call helper method
HelperMethod();
helper_success = true;
}
catch(Exception e)
{
// check if e is a transient exception. If so, set automatic_retry = true
}
if (automatic_retry)
{ //try catch statement for second process.
try
{
HelperMethod();
}
catch(Exception e)
{
throw;
}
}
Here's another pattern:
// set up state for first attempt
if(!HelperMethod(false)) {
// set up state for second attempt
HelperMethod(true);
// no need to try catch since you're just throwing anyway
}
Here, HelperMethod is
bool HelperMethod(bool throwOnFailure)
and the return value indicates whether or not success occurred (i.e., false indicates failure and true indicates success). You could also do:
// could wrap in try/catch
HelperMethod(2, stateChanger);
where HelperMethod is
void HelperMethod(int numberOfTries, StateChanger[] stateChanger)
where numberOfTries indicates the number of times to try before throwing an exception and StateChanger[] is an array of delegates that will change the state for you between calls (i.e., stateChanger[0] is called before the first attempt, stateChanger[1] is called before the second attempt, etc.)
This last option indicates that you might have a smelly setup though. It looks like the class that is encapsulating this process is responsible for both keeping track of state (which employee to look up) as well as looking up the employee (HelperMethod). By SRP, these should be separate.
Of course, you need to a catch a more specific exception than you currently are (don't catch the base class Exception!) and you should just throw instead of throw e if you need to rethrow the exception after logging, cleanup, etc.
You could emulate C#'s TryParse method signatures:
class Program
{
static void Main(string[] args)
{
Exception ex;
Console.WriteLine("trying 'ex'");
if (TryHelper("ex", out ex))
{
Console.WriteLine("'ex' worked");
}
else
{
Console.WriteLine("'ex' failed: " + ex.Message);
Console.WriteLine("trying 'test'");
if (TryHelper("test", out ex))
{
Console.WriteLine("'test' worked");
}
else
{
Console.WriteLine("'test' failed: " + ex.Message);
throw ex;
}
}
}
private static bool TryHelper(string s, out Exception result)
{
try
{
HelperMethod(s);
result = null;
return true;
}
catch (Exception ex)
{
// log here to preserve stack trace
result = ex;
return false;
}
}
private static void HelperMethod(string s)
{
if (s.Equals("ex"))
{
throw new Exception("s can be anything except 'ex'");
}
}
}
Another way is to flatten the try/catch blocks, useful if you're using some exception-happy API:
public void Foo()
{
try
{
HelperMethod("value 1");
return; // finished
}
catch (Exception e)
{
// possibly log exception
}
try
{
HelperMethod("value 2");
return; // finished
}
catch (Exception e)
{
// possibly log exception
}
// ... more here if needed
}
An option for retry (that most people will probably flame) would be to use a goto. C# doesn't have filtered exceptions but this could be used in a similar manner.
const int MAX_RETRY = 3;
public static void DoWork()
{
//Do Something
}
public static void DoWorkWithRetry()
{
var #try = 0;
retry:
try
{
DoWork();
}
catch (Exception)
{
#try++;
if (#try < MAX_RETRY)
goto retry;
throw;
}
}
In this case you know this "exception" probably will happen so I would prefer a simple approach an leave exceptions for the unknown events.
//run initial process
try
{
//initial information used in helper method
string s1 = "value 1";
//call helper method
if(!HelperMethod(s1))
{
//backup information if first process generates an exception in the helper method
string s2 = "value 2";
if(!HelperMethod(s2))
{
return ErrorOfSomeKind;
}
}
return Ok;
}
catch(ApplicationException ex)
{
throw;
}
I know that I've done the above nested try catch recently to handle decoding data where two third party libraries throw exceptions on failure to decode (Try json decode, then try base64 decode), but my preference is to have functions return a value which can be checked.
I generally only use the throwing of exceptions to exit early and notify something up the chain about the error if it's fatal to the process.
If a function is unable to provide a meaningful response, that is not typically a fatal problem (Unlike bad input data).
It seems like the main risk in nested try catch is that you also end up catching all the other (maybe important) exceptions that might occur.

How can I improve this exception retry scenario?

I have a web service method I am calling which is 3rd party and outside of my domain. For some reason every now and again the web service fails with a gateway timeout. Its intermittent and a call to it directly after a failed attempt can succeed.
Now I am left with a coding dilemma, I have code that should do the trick, but the code looks like amateur hour, as you'll see below.
Is this really bad code, or acceptable given the usage? If its not acceptable, how can I improve it?
Please try hard to keep a straight face while looking at it.
try
{
MDO = OperationsWebService.MessageDownload(MI);
}
catch
{
try
{
MDO = OperationsWebService.MessageDownload(MI);
}
catch
{
try
{
MDO = OperationsWebService.MessageDownload(MI);
}
catch
{
try
{
MDO = OperationsWebService.MessageDownload(MI);
}
catch
{
try
{
MDO = OperationsWebService.MessageDownload(MI);
}
catch (Exception ex)
{
// 5 retries, ok now log and deal with the error.
}
}
}
}
}
You can do it in a loop.
Exception firstEx = null;
for(int i=0; i<5; i++)
{
try
{
MDO = OperationsWebService.MessageDownload(MI);
firstEx = null;
break;
}
catch(Exception ex)
{
if (firstEx == null)
{
firstEx = ex;
}
Thread.Sleep(100 * (i + 1));
}
}
if (firstEx != null)
{
throw new Exception("WebService call failed after 5 retries.", firstEx);
}
Here's another way you might try:
// Easier to change if you decide that 5 retries isn't right for you
Exception exceptionKeeper = null;
for (int i = 0; i < MAX_RETRIES; ++i)
{
try
{
MDO = OperationsWebService.MessageDownload(MI);
break; // correct point from Joe - thanks.
}
catch (Exception ex)
{
exceptionKeeper = ex;
// 5 retries, ok now log and deal with the error.
}
}
I think it documents the intent better. It's less code as well; easier to maintain.
All of the answers so far assume that the reaction to any exception should be to retry the operation. This is a good assumption right up until it's a false assumption. You could easily be retrying an operation that is damaging your system, all because you didn't check the exception type.
You should almost never use a bare "catch", nor "catch (Exception ex). Catch a more-specific exception - one you know you can safely recover from.
Try a loop, with some kind of limit:
int retryCount = 5;
var done = false;
Exception error = null;
while (!done && retryCount > 0)
{
try
{
MDO = OperationsWebService.MessageDownload(MI);
done = true;
}
catch (Exception ex)
{
error = ex;
}
if (done)
break;
retryCount--;
}
You should use recursion (or a loop), and should only retry if you got the error you expected.
For example:
static void TryExecute<TException>(Action method, Func<TException, bool> retryFilter, int maxRetries) where TException : Exception {
try {
method();
} catch(TException ex) {
if (maxRetries > 0 && retryFilter(ex))
TryExecute(method, retryFilter, maxRetries - 1);
else
throw;
}
}
EDIT: With a loop:
static void TryExecute<TException>(Action method, Func<TException, bool> retryFilter, int maxRetries) where TException : Exception {
while (true) {
try {
method();
return;
} catch(TException ex) {
if (maxRetries > 0 && retryFilter(ex))
maxRetries--;
else
throw;
}
}
}
You can try to prevent future errors in retryFilter, perhaps by Thread.Sleep.
If the last retry fails, this will throw the last exception.
Here is some retry logic we are using. We don't do this a lot and I was going to pull it out and document it as our Retry Pattern/Standard. I had to wing it when I first wrote it so I came here to see if I was doing it correctly. Looks like I was. The version below is fully commented. See below that for an uncommented version.
#region Retry logic for SomeWebService.MyMethod
// The following code wraps SomeWebService.MyMethod in retry logic
// in an attempt to account for network failures, timeouts, etc.
// Declare the return object for SomeWebService.MyMethod outside of
// the following for{} and try{} code so that we have it afterwards.
MyMethodResult result = null;
// This logic will attempt to retry the call to SomeWebService.MyMethod
for (int retryAttempt = 1; retryAttempt <= Config.MaxRetryAttempts; retryAttempt++)
{
try
{
result = SomeWebService.MyMethod(myId);
// If we didn't get an exception, then that (most likely) means that the
// call was successful so we can break out of the retry logic.
break;
}
catch (Exception ex)
{
// Ideally we want to only catch and act on specific
// exceptions related to the failure. However, in our
// testing, we found that the exception could be any type
// (service unavailable, timeout, database failure, etc.)
// and attempting to trap every exception that was retryable
// was burdensome. It was easier to just retry everything
// regardless of the cause of the exception. YMMV. Do what is
// appropriate for your scenario.
// Need to check to see if there will be another retry attempt allowed.
if (retryAttempt < Config.MaxRetryAttempts)
{
// Log that we are re-trying
Logger.LogEvent(string.Format("Retry attempt #{0} for SomeWebService.MyMethod({1})", retryAttempt, myId);
// Put the thread to sleep. Rather than using a straight time value for each
// iteration, we are going to multiply the sleep time by how many times we
// have currently tried to call the method. This will allow for an easy way to
// cover a broader range of time without having to use higher retry counts or timeouts.
// For example, if MaxRetryAttempts = 10 and RetrySleepSeconds = 60, the coverage will
// be as follows:
// - Retry #1 - Sleep for 1 minute
// - Retry #2 - Sleep for 2 minutes (covering three minutes total)
// - Retry #10 - Sleep for 10 minutes (and will have covered almost an hour of downtime)
Thread.Sleep(retryAttempt * Config.RetrySleepSeconds * 1000);
}
else
{
// If we made it here, we have tried to call the method several
// times without any luck. Time to give up and move on.
// Moving on could either mean:
// A) Logging the exception and moving on to the next item.
Logger.LogError(string.Format("Max Retry Attempts Exceeded for SomeWebService.MyMethod({0})", MyId), ex);
// B) Throwing the exception for the program to deal with.
throw new Exception(string.Format("Max Retry Attempts Exceeded for SomeWebService.MyMethod({0})", myId), ex);
// Or both. Your code, your call.
}
}
}
#endregion
I like Samuel Neff's example of using an exception variable to see if it completely failed or not. That would have made some of the evaluations in my logic a little simpler. I could go either way. Not sure that either way has a significant advantage over the other. However, at this point in time, I'm not going to change how we do it. The important thing is to document what you are doing and why so that some idiot doesn't come through behind you and muck with everything.
Just for kicks though, to get a better idea if the code is any shorter or cleaner one way or the other, I pulled out all the comments. They came out exactly the same number of lines. I went ahead and compiled the two versions and ran them through Reflector Code Metrics and got the following:
Metric: Inside-Catch / Outside-For
CodeSize: 197 / 185
CyclomaticComplexity: 3 / 3
Instructions: 79 / 80
Locals: 6 / 7
Final exception logic inside the catch (22 lines):
MyMethodResult result = null;
for (int retryAttempt = 1; retryAttempt <= Config.MaxRetryAttempts; retryAttempt++)
{
try
{
result = SomeWebService.MyMethod(myId);
break;
}
catch (Exception ex)
{
if (retryAttempt < Config.MaxRetryAttempts)
{
Logger.LogEvent(string.Format("Retry attempt #{0} for SomeWebService.MyMethod({1})", retryAttempt, myId);
Thread.Sleep(retryAttempt * Config.RetrySleepSeconds * 1000);
}
else
{
Logger.LogError(string.Format("Max Retry Attempts Exceeded for SomeWebService.MyMethod({0})", MyId), ex);
throw new Exception(string.Format("Max Retry Attempts Exceeded for SomeWebService.MyMethod({0})", myId), ex);
}
}
}
Final exception logic after the for-loop (22 lines):
MyMethodResult result = null;
Exception retryException = null;
for (int retryAttempt = 1; retryAttempt <= Config.MaxRetryAttempts; retryAttempt++)
{
try
{
result = SomeWebService.MyMethod(myId);
retryException = null;
break;
}
catch (Exception ex)
{
retryException = ex;
Logger.LogEvent(string.Format("Retry attempt #{0} for SomeWebService.MyMethod({1})", retryAttempt, myId);
Thread.Sleep(retryAttempt * Config.RetrySleepSeconds * 1000);
}
}
if (retryException != null)
{
Logger.LogError(string.Format("Max Retry Attempts Exceeded for SomeWebService.MyMethod({0})", MyId), ex);
throw new Exception(string.Format("Max Retry Attempts Exceeded for SomeWebService.MyMethod({0})", myId), ex);
}
I'm using the following generic method for a retry scenario. I especially want to draw attention to the PreserveStackTrace method which helps to preserve the full call stack trace, because (as I learned the hard way) neither throw or throw ex yields the complete call stack trace information.
public static void RetryBeforeThrow<T>(Action action, int retries, int timeout) where T : Exception
{
int tries = 1;
do
{
try
{
action();
return;
}
catch (T ex)
{
if (retries <= 0)
{
PreserveStackTrace(ex);
throw;
}
Thread.Sleep(timeout);
}
}
while (tries++ < retries);
}
/// <summary>
/// Sets a flag on an <see cref="T:System.Exception"/> so that all the stack trace information is preserved
/// when the exception is re-thrown.
/// </summary>
/// <remarks>This is useful because "throw" removes information, such as the original stack frame.</remarks>
/// <see href="http://weblogs.asp.net/fmarguerie/archive/2008/01/02/rethrowing-exceptions-and-preserving-the-full-call-stack-trace.aspx"/>
public static void PreserveStackTrace(Exception ex)
{
MethodInfo preserveStackTrace = typeof(Exception).GetMethod("InternalPreserveStackTrace", BindingFlags.Instance | BindingFlags.NonPublic);
preserveStackTrace.Invoke(ex, null);
}
As everyone else has pointed out the correct approach is to wrap your try/catch inside some loop with a MAX_RETRY of some sort.
You might also consider adding a timeout between each loop iteration. Otherwise you're likely to burn through your retry counter before the transient issue has had a chance to resolve itself.
It seems you have the answers you need, but I thought I'd post this link, What is an Action Policy?, that I found to provide a much more elegant solution. Lokad has some rather labyrinthine implementations, but the guy's logic is pretty solid, and the end code you'd end up writing is pretty and simple.
int cnt=0;
bool cont = true;
while (cont)
{
try
{
MDO = OperationsWebService.MessageDownload(MI);
cont = false;
}
catch (Exception ex)
{
++cnt;
if (cnt == 5)
{
// 5 retries, ok now log and deal with the error.
cont = false;
}
}
}
UPDATED : Fixed code based on comments.

Categories

Resources