【问题标题】:Whats the best solution to implement retry on Servicestack JsonServiceClient Get method?在 Servicestack JsonServiceClient Get 方法上实现重试的最佳解决方案是什么?
【发布时间】:2015-03-18 03:51:42
【问题描述】:

在我的项目中,我使用 Servicestack 从特定 URL 获取数据,此过程是可配置的,我在单独的线程中调用获取数据,如果引发超时错误,我想实现重试。我在 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);

【问题讨论】:

  • 感谢@abatishchev,我已经看到了这个API,它真的很棒,但是在这种情况下不能使用它,因为我想针对特定情况实施重试,并且根据条件实现不同的重试尝试次数。

标签: c# servicestack


【解决方案1】:

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

我同意你的做法。扩展 JsonServiceClient 并实现您的重试逻辑,这是实现可重用性和可维护性的最佳方法,前提是您已经实现了如下所示的内容。

扩展JsonServiceClient

扩展JsonServiceClient,以便您可以合并自己的重试逻辑。然后它很容易在您的代码中重用,而无需在每次您想要发出请求时使用while 和计数器。

如果您在此处看到JsonServiceClientBase.cs 代码,您会注意到所有动词方法如Get&lt;TResponse&gt; Post&lt;TResponse&gt; ... Put 等都是通过Send&lt;TResponse&gt;(object request) 方法调用的。

因此,通过重写这个方法,我们可以很容易地在所有动词上实现重试功能,而不用改变它的用法。

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;
            }
        }
    }
}

用法:

  • 将对JsonServiceClient 的引用替换为MyJsonServiceClientWithRetry
  • 设置尝试次数
  • 正常使用客户端。 (包装在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)
}

注意事项:

如果WebServiceException 抛出状态码为 400 或 401,我不会重试,因为在不更改它的情况下再次尝试此请求似乎是多余的。显然你可以自定义这个逻辑。

如果连接超时,则会将超时错误作为WebException 抛出。如果您想专门处理这种情况。

希望对你有帮助。

【讨论】:

  • 谢谢@Scott,我想需要一个简单的改变。应该在 Send 上覆盖 Get 方法。
  • @Peyman 不客气。您不需要覆盖Get,因为底层Get 方法调用了您已覆盖的Send&lt;TResponse&gt; 方法。我添加了一个小修复,因为我错过了Send 方法的参数。但是上面的代码应该允许调用 Get、Put、Post、Delete 和 Send,而不需要覆盖每个动词方法。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-05-01
  • 1970-01-01
  • 2014-09-18
  • 1970-01-01
相关资源
最近更新 更多