12

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?

Chris Cudmore
  • 29,793
  • 12
  • 57
  • 94
James Jeffery
  • 12,093
  • 19
  • 74
  • 108
  • 1
    a conditional loop? if you aren't handling the exception, why are you putting it in a try/catch – davidosomething Feb 09 '10 at 17:58
  • 5
    Insanity is doing the same thing twice and expecting different results. I say that if you get an exception, almost always the best thing to do is to tell the user and let *them* solve the problem. – Eric Lippert Feb 09 '10 at 18:10
  • 3
    @Eric I am guessing he's doing something like running a service that connects to another service. If the connection fails, it throws and exception. He wants to then retry the connection because there could be any number of reasons not associated with his own code for the failure (server down, network down, routing glitch, etc..). Notifying the user is kind of silly, since the user will only do the same thing, attempt to reconnect again. – Erik Funkenbusch Feb 09 '10 at 18:26
  • @Mystere Man: The user might do something else. The user might try to hit a web page to see if there is any network connectivity at all. THe user might pick up the phone and call helpdesk to ask if the network routers in the basement are messed up. The user might think "oh, wait, I haven't rebooted since I upgraded those drivers, maybe something is messed up". The user might do any number of things that you have no ability to predict; let them make the choice of what to do when trouble is detected. They have more information than you. – Eric Lippert Feb 09 '10 at 18:36
  • 3
    @Eric: While I agree that at some point the user may have to get involved (and that point might be right away), all too often in such scenarios the problem just "goes away by itself" because the problem was not local, and nothing wrong with the code. The point is, while there are times you want the user to do something, there are other times you want to just keep trying and then give up after a while, or reduce the frequency of your tries. That way, when the problem is corrected, the system automatically starts working again. – Erik Funkenbusch Feb 09 '10 at 19:44

9 Answers9

17

check this SO answer.. hope that helps u

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

Community
  • 1
  • 1
Jeeva Subburaj
  • 1,881
  • 2
  • 18
  • 26
  • 3
    +1: This one gets my upvote. It's the kind of thing delegates live for. – Robert Harvey Feb 09 '10 at 18:06
  • 1
    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 Feb 09 '10 at 18:14
  • -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 Feb 10 '10 at 19:38
  • The *else* inside catch block is redundant – Yurii Hohan Nov 22 '11 at 15:24
  • @John Saunders, you can easily make this class generic and catch a specific exception, the beauty is in the idea, tuning it is up to you – Yurii Hohan Nov 22 '11 at 15:59
  • @Hohhi: no, it's a bad example that some poor soul will copy and paste without realizing that he should "tune" it first. – John Saunders Nov 22 '11 at 16:03
6

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++;
         }
    }
Brian Leahy
  • 34,677
  • 12
  • 45
  • 60
James
  • 9,774
  • 5
  • 34
  • 58
  • 1
    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 Feb 09 '10 at 18:03
  • Agree with David B. Swallowed exceptions are pure evil. – Nick Monkman Feb 09 '10 at 18:06
  • 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. – James Feb 09 '10 at 18:09
  • there i added the finally block for him – Brian Leahy Feb 09 '10 at 18:13
2

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.

Gabriel Magana
  • 4,338
  • 24
  • 23
2

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
  • 47,638
  • 12
  • 72
  • 142
2

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
  • 11,845
  • 7
  • 49
  • 69
  • 1
    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 Feb 09 '10 at 18:00
1

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
  • 811,555
  • 193
  • 1,581
  • 1,452
1

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.

CaffGeek
  • 21,856
  • 17
  • 100
  • 184
  • 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 Feb 10 '10 at 19:40
1

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
  • 637
  • 4
  • 9
  • Except that the internet connection might start failing after you've tried to detect it and before you use it. – J W Feb 11 '10 at 13:18
1

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
  • 49,714
  • 13
  • 63
  • 88
  • 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 Feb 09 '10 at 18:04
  • @Mathews : There's no `Integer` in C#. It is either `int` or `Int32`. – missingfaktor Feb 09 '10 at 18:07
  • -1: You should not be catching `Exception`. Catch something more specific that you know how to recover from. – John Saunders Feb 10 '10 at 19:40
  • 1
    @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 Feb 10 '10 at 20:50
  • @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 Feb 10 '10 at 21:40