简体   繁体   中英

Whats the best solution to implement retry on Servicestack JsonServiceClient Get method?

In my project I'm using Servicestack to fetch data from specific URL, this procedure is configurable and I call the fetch data in separate thread, I want to implement retry if the Timeout error is raised. I created wrapper class on JsonServiceClient and implement retry there, but I want to know what's the best solution for this approach.

var _client = new JsonServiceClient { Timeout = timeout };
var counter = 0;
do
{
    try
    {
        result = _client.Get<TResponse>(url);
        break;
    }
    catch (Exception exp)
    {
        //Logging exception
    }
}
while (++counter < this.Retry);

I created wrapper class on JsonServiceClient and implement retry there, but I want to know what's the best solution for this approach.

I agree with your approach. Extending the JsonServiceClient and implementing your retry logic there is the best approach for reusability and maintainability, provided you have implemented something like below.

Extend JsonServiceClient

Extend the JsonServiceClient so you can incorporate your own retry logic. Then it is easily reusable in your code without the use of while and counters each time you want to make a request.

If you see the JsonServiceClientBase.cs code here, you will note that all the verb methods such as Get<TResponse> Post<TResponse> ... Put etc. all call through the Send<TResponse>(object request) method.

Therefore by overwriting this method, we can implement the retry functionality easily on all verbs, without changing it's usage.

public class MyJsonServiceClientWithRetry : JsonServiceClient
{

    public MyJsonServiceClientWithRetry()
    {
    }

    public MyJsonServiceClientWithRetry(int retryAttempts)
    {
        RetryAttempts = retryAttempts;
    }

    public MyJsonServiceClientWithRetry(string baseUri) : base(baseUri)
    {
    }

    public MyJsonServiceClientWithRetry(string syncReplyBaseUri, string asyncOneWayBaseUri) : base(syncReplyBaseUri, asyncOneWayBaseUri)
    {
    }


    // Retry attempts property
    public int RetryAttempts { get; set; }


    public override TResponse Send<TResponse> (string httpMethod, string relativeOrAbsoluteUrl, object request)
    {
        int attempts = RetryAttempts;

        while(true) 
        {
            attempts--;

            try {
                return base.Send<TResponse> (httpMethod, relativeOrAbsoluteUrl, request);
            } catch (WebServiceException webException) {

                // Throw the exception if the number of retries is 0 or we have made a bad request, or are unauthenticated
                if(attempts == 0 || webException.StatusCode == 400 || webException.StatusCode == 401)
                    throw;

            } catch (Exception exception) {

                // Throw the exception if the number of retries is 0
                if(attempts == 0) 
                    throw;
            }
        }
    }
}

Usage:

  • Replace reference to JsonServiceClient with MyJsonServiceClientWithRetry
  • Set the attempt count
  • Use the client as normal. (Wrap in try/catch block to catch exceptions after retries exceeded)
var client = new MyJsonServiceClientWithRetry ("http://localhost:8080") {
    RetryAttempts = 3,
    Timeout = new TimeSpan(0, 0, 30)
};


try
{
    var myRequestDto = new MyRequest {
        Name = "John Smith"
    };

    // This request will be attempted 3 times (if there is an exception)
    var response = client.Get<MyResponse>(myRequestDto);

    // Do something with response ...

} catch(Exception ex) {
    // Exception thrown here after 3 attempts (or immediately if status code is 400 / 401)
}

Notes:

I don't retry if a WebServiceException is thrown with status code 400 or 401, because it seems redundant to try this request again without changing it. Obviously you can customise this logic.

If the connection times out then the timeout error is thrown as a WebException . In case you want to handle this case specifically.

I hope that helps.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM