views:

328

answers:

9
+10  Q: 

Try, Catch Problem

I've noticed this problem happening a lot in most things I do, so I'm thinking there must be a design pattern for this.

Basically if an exception is thrown, attempt to solve the problem and retry. If I place it in the try, all it will do is catch the exception, but I want to retry whatever it was doing and if it fails again, retry again a certain number of times.

Is there a common pattern for this sort of stuff?

+2  A: 

try/catch inside a loop, with a counter for retries?

EDIT: And your requirement of "retry whatever it was doing," you need custom logic for that, how to retry varies wildly (ie, reopen a stream, recreate the object, pause for X milliseconds, etc...), so you need it's own try/catch inside a loop for every atomic operation.

By "atomic operation" I mean a set of related statements, such as read a file. The whole file read into memory might be an atomic operation, for example.

gmagana
+2  A: 

On some limited basis, you might want to put your try/catch into a loop, and force break if is ultimately successful. Such might be for internet access testing and you want user to have another attempt at connection.

DRapp
+16  A: 

check this SO answer.. hope that helps u

http://stackoverflow.com/questions/1563191/c-cleanest-way-to-write-retry-logic

public static class RetryUtility
{
   public static void RetryAction(Action action, int numRetries, int retryTimeout)
   {
       if(action == null)
           throw new ArgumenNullException("action"); 

       do
       {
          try 
          {  
              action(); 
              return;  
          }
          catch
          { 
              if(numRetries <= 0) 
                  throw;  // Avoid silent failure
              else
              {
                  Thread.Sleep(retryTimeout);
                  numRetries--;
              }
          }
       } 
       while(numRetries > 0);
   }
}

Call

RetryUtility.RetryAction( () => SomeFunctionThatCanFail(), 3, 1000 );

Credit goes to LBushkin

Jeeva S
+1: This one gets my upvote. It's the kind of thing delegates live for.
Robert Harvey
I was about to respond to the second answer and say, "Well, I'd just abstract it into a method that takes a delegate and add a retry counter.." Then I scrolled down. Excellent answer.
Marc Bollinger
-1: the blanket catch makes no sense, even if it only happens `numRetries` times. You have no idea which exception was thrown, or whether it makes any sense to retry.
John Saunders
+6  A: 

This runs indefinately but it would be easy to add a loop counter to the while clause

    var solved = false;
    var tries = 0;

    while (!solved)
    {
         try
         {
            //Do Something
            solved = true;
         }
         catch
         {
             //Fix error
         } 
         finally
         {
              if(solved || IsRediculous(tries))
                 break;

              tries++;
         }
    }
JamesB
That will loop forever!
Dolph
@Dolph Mathews: Of course! If at first you don't succeed...
Mark Byers
Yes, it will loop forever until it hits solved = true;
Pauk
You should really look at rethinking your approach. Catching the exception is very bad. This could be an infinite loop. The user should understand the error and then develop to prevent the exception. The very least an attempt number should be used to make sure the loop will exit after x number of attempts.
David Basarab
Agree with David B. Swallowed exceptions are pure evil.
Nick Monkman
I was assuming that he wanted to swallow the exception, and had a valid reason to do so, as well as a way to fix it.
JamesB
there i added the finally block for him
Brian Leahy
+1  A: 

Yes, it is quite common to have a loop with a number of retries where you break out of the loop on success. A couple of things:

You might want to add a delay before retrying so that you don't use up all your retries in just a few milliseconds before the temporary problem had time to fix itself.

If you eventually fail, you should throw the first exception you caught, not the last one. The second exception could be the result of failing to recover correctly from the first failure and might not help to debug the original problem.

Mark Byers
+2  A: 

Something like this, maybe:

int MAX_RETRIES = 5;
for (var attempt=1; attempt <= MAX_RETRIES; attempt++) {
    try {
        DoSomethingThatMightThrow();
    }
    catch (AnExceptionIKnowHowToHandle) {
        if (attempt < MAX_RETRIES)
             continue;

        throw;
    }
}
Seth Petry-Johnson
Mark makes a good point in his answer. Depending on the scenario you might want to store a reference to the original exception and then re-throw it (or just throw the last exception, passing the original one as the InnerException) if you exceed your max retries. Also, as Mark said, you might want to add a delay between the retries if your expected exceptions could be caused by resource contention.
Seth Petry-Johnson
+1  A: 

Depends what you are trying, but typically you want to check for the possibility of an exception happening PRIOR to executing the code that could cause an exception.

For example, check that a file exists before accessing it, and create it (or whatever) if it doesn't.

Chad
File.Exists can return false if the file doesn't exist, or if the file can't be accessed. You'll never know which of the two it is unless you try to open the file. That way, you'll also get an exception with details on why the file can't be opened (at least, you will if you use ex.ToString()).
John Saunders
+1  A: 

Are you sure exception handling is the proper methodology here? If you can "solve the problem" you can probably detect the error condition prior to calling the exception-generatiing code.

Exception handling is most natural for things which are truly exceptional. A failed Internet connection (as in the previous answer) is something that can be detected and handled before calling exception-throwing code.

Nick Monkman
Except that the internet connection might start failing after you've tried to detect it and before you use it.
J W
+1  A: 

Coding what others have already mentioned:

var success = false;
var attempts = 0;
var maxAttempts = 0;

do {
  attempts++;

  try {
    /* your code */
    success = condition;
  } catch(SuperciliousException e) {
    /* recover */
  }
} while(!success && attempts < maxAttempts);
Dolph
This is a better solution, since you are bringing in attempts. However the user should understand what the exception is, and try to prevent it or catch that exception. +1 for the Attempts.
David Basarab
@Mathews : There's no `Integer` in C#. It is either `int` or `Int32`.
missingfaktor
I wrote this in Java, feel free to edit to C#
Dolph
Yeah, edited. +1
missingfaktor
-1: You should not be catching `Exception`. Catch something more specific that you know how to recover from.
John Saunders
@John Saunders: The OP is asking about C#, and I wrote near-pseudo-code in Java. I think the OP knows what he needs to catch and can fill it in accordingly. Furthermore, the OP doesn't specify what the exception *is* beyond "an exception."
Dolph
@Dolph: People copy and paste examples. If you mean the OP should catch "_specific exception you know how to handle_" then please say so instead of saying the OP should catch `Exception`. Whichever you say, someone will do it, so you'd just as well say they should do something harmless.
John Saunders