Search code examples
c#.netwcf-4retrypolicywcf-data-services-client

Retry logic with multiple methods


I am implementing retry logic for WCF services on the client side. I have multiple operations in WCF service with various input parameters and return types.

I created a wrapper that can make a call to these certain methods that have no return type(void) using Action delegate. Is there any way to call methods that have various input parameters and return type.

Or is there any logic to implement retry functionality on the client side that can handle multiple WCF services.

Class RetryPolicy<T>
{
 public T ExecuteAction(Func<T> funcdelegate,int? pretrycount = null,bool? pexponenialbackoff = null)
        {
            try
            {
                var T = funcdelegate();
                return T;
            }
            catch(Exception e)
            {
                if (enableRetryPolicy=="ON" && TransientExceptions.IsTransient(e))
                {

                    int? rcount = pretrycount == null ? retrycount : pretrycount;
                    bool? exbackoff = pexponenialbackoff == null ? exponentialbackoff : pexponenialbackoff;

                    int rt = 0;
                    for (rt = 0; rt < rcount; rt++)
                    {
                        if (exponentialbackoff)
                        {
                            delayinms = getWaitTimeExp(rt);
                        }

                        System.Threading.Thread.Sleep(delayinms);

                        try
                        {
                            var T = funcdelegate();
                            return T;
                        }
                        catch(Exception ex)
                        {
                            if (TransientExceptions.IsTransient(ex))
                            {

                                int? rcount1 = pretrycount == null ? retrycount : pretrycount;
                                bool? exbackoff1 = pexponenialbackoff == null ? exponentialbackoff : pexponenialbackoff;

                            }
                            else
                            {
                                throw;
                            }
                        }
                    }

                    //throw exception back to caller if exceeded number of retries
                    if(rt == rcount)
                    {
                        throw;
                    }
                }
                else
                {
                    throw;
                }
            }
            return default(T);
        }
}  

I use above method and make a call

  public string GetCancelNumber(string property, Guid uid)
        {
            RetryPolicy<string> rp = new RetryPolicy<string>();
            return rp.ExecuteAction(()=>Channel.GetCancelNumber(property, uid, out datasetarray));
        }

I keep getting error "cannot use ref or out parameters in anonymous delegate"


Solution

  • Here is an example of a simple Retry method:

    bool Retry(int numberOfRetries, Action method)
    {
        if (numberOfRetries > 0)
        {
            try
            {
                method();
                return true;
            }
            catch (Exception e)
            {
                // Log the exception
                LogException(e); 
    
                // wait half a second before re-attempting. 
                // should be configurable, it's hard coded just for the example.
                Thread.Sleep(500); 
    
                // retry
                return Retry(--numberOfRetries, method);
            }
        }
        return false;
    }
    

    It will return true if the method succeed at least once, and log any exception until then. If the method fails on every retry, it will return false.

    (Succeed means completed without throwing an exception in this case)

    How to use:

    Assuming sample Action (void method) and sample Func (a method with a return type)

    void action(int param) {/* whatever implementation you want */}
    int function(string param) {/* whatever implementation you want */}
    

    Execute a function:

    int retries = 3;
    int result = 0;
    var stringParam = "asdf";
    if (!Retry(retries, () => result = function(stringParam)))
    {
        Console.WriteLine("Failed in all {0} attempts", retries);
    }
    else
    {
        Console.WriteLine(result.ToString());
    }
    

    Execute an action:

    int retries = 7;
    int number = 42;
    if (!Retry(retries, () => action(number)))
    {
        Console.WriteLine("Failed in all {0} attempts", retries);
    }
    else
    {
        Console.WriteLine("Success");
    }
    

    Execute a function with an out parameter (int function(string param, out int num)):

    int retries = 3;
    int result = 0;
    int num = 0;
    var stringParam = "asdf";
    if (!Retry(retries, () => result = function(stringParam, out num)))
    {
        Console.WriteLine("Failed in all {0} attempts", retries);
    }
    else
    {
        Console.WriteLine("{0} - {1}", result, num);
    }