简体   繁体   English

什么是在Servicestack JsonServiceClient Get方法上实现重试的最佳解决方案?

[英]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. 在我的项目中,我使用Servicestack从特定URL获取数据,此过程是可配置的,我在单独的线程中调用获取数据,如果引发Timeout错误,我想实现重试。 I created wrapper class on JsonServiceClient and implement retry there, but I want to know what's the best solution for this approach. 我在JsonServiceClient上创建了包装类并在那里实现了重试,但我想知道这种方法的最佳解决方案是什么。

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. 我在JsonServiceClient上创建了包装类并在那里实现了重试,但我想知道这种方法的最佳解决方案是什么。

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. 扩展JsonServiceClient并实现重试逻辑,这是可重用性和可维护性的最佳方法,前提是您已实现如下所示。

Extend JsonServiceClient 扩展JsonServiceClient

Extend the JsonServiceClient so you can incorporate your own retry logic. 扩展JsonServiceClient以便您可以合并自己的重试逻辑。 Then it is easily reusable in your code without the use of while and counters each time you want to make a request. 然后,您可以轻松地在代码中重复使用, while无需在每次要求时使用while和counter。

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. 如果你在这里看到JsonServiceClientBase.cs代码,你会注意到所有动词方法,如Get<TResponse> Post<TResponse> ... Put等都通过Send<TResponse>(object request)方法调用。

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 JsonServiceClient替换对JsonServiceClientMyJsonServiceClientWithRetry
  • Set the attempt count 设置尝试次数
  • Use the client as normal. 正常使用客户端。 (Wrap in try/catch block to catch exceptions after retries exceeded) (包含在try/catch块中以在超过重试后捕获异常)
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. 如果抛出状态代码为400或401的WebServiceException我不会重试,因为在不更改它的情况下再次尝试此请求似乎是多余的。 Obviously you can customise this logic. 显然你可以自定义这个逻辑。

If the connection times out then the timeout error is thrown as a WebException . 如果连接超时,则会将超时错误作为WebException抛出。 In case you want to handle this case specifically. 如果您想特别处理此案例。

I hope that helps. 我希望有所帮助。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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