How can I improve this exception retry scenario?

前端 未结 10 1512
暗喜
暗喜 2020-12-13 19:39

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 i

相关标签:
10条回答
  • 2020-12-13 20:29

    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);
    }
    
    0 讨论(0)
  • 2020-12-13 20:31

    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);
    }
    
    0 讨论(0)
  • 2020-12-13 20:32

    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.

    0 讨论(0)
  • 2020-12-13 20:35

    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.

    0 讨论(0)
提交回复
热议问题