【问题标题】:Throttle method in C# [closed]C# 中的节流方法 [关闭]
【发布时间】:2019-01-26 12:30:17
【问题描述】:

我有方法可以向某些 3rd 方 API 发出请求并从它返回响应。 由于这个 API 每 1 分钟只允许 50 次调用,我想限制我对这个 API 的请求。

目前我正在考虑使用 Polly 并在我的代码中添加类似包装器的东西

var policy = Policy.Handle<HttpRequestException>()
                   .WaitAndRetryForever(retryAttempt => TimeSpan.FromMinutes(1));

var response = await policy.ExecuteAsync(async () => await DoApiCallAsync()
                           .ConfigureAwait(false));

return response;

但也许这里有更好的方法。

【问题讨论】:

  • 您当前的代码有效吗?如果是这样,codereview.stackexchange.com 可能更合适。如果它不起作用,您需要明确说明什么不起作用。
  • 一般来说:WaitAndRetryForever 听起来很危险。
  • @Stefan,嗯,是的,也许在这里至少 3 次就够了...

标签: c# api httprequest throttling


【解决方案1】:

Polly 很好,我们在我们的基础设施中使用它作为我们微服务之间的重试机制,但是我不推荐.WaitAndRetryForever,因为这听起来真的像@Stefan 说的那样危险。如果第 3 方 API 在 30 分钟的维护/停机/无响应中出现会发生什么我知道这种情况不会经常发生,但仍然会发生。

我建议使用Polly 来解决网络问题。例如,第 3 方 API 可能的网络停机时间,但与节流无关。

关于节流,我建议创建一些 queue based 模式,您可以在其中存储您的请求并以给定的速率处理它们。

遗憾的是,这还有两个缺点:

  1. 您需要在您的终端实现一些逻辑,以使该队列不会变得非常大,并使您的进程消耗大量内存。
  2. 如果有人等待超过一定时间才能收到他们的回复,这可能会影响用户体验。

由于我不知道您的 API 的性质,因此我只能接受建议,您必须决定这是否适合您。祝你好运!

注意: .waitAndRetryForever 如果您将其用于内部通信并且想要放松您的service-level agreement,那么它还不错。 (你不希望你的整个基础设施仅仅因为一个服务死掉了)。

【讨论】:

    【解决方案2】:

    我更喜欢控制一切(根据需要自定义)

    您还可以扩展工作人员以并行发出多个请求

    例子

    Worker worker = new Worker();
    worker.OnRetry += (id) =>
    {
      //called when error occurs
      //here you can wait as you want and send next request
    };
    worker.OnRespnse += (sender, success) =>
    {
      //called on response
      //customize success depend on response status-code/body
      //here you can wait as you want and send next request
    };
    worker.Start("request body");
    //you can start this worker over and over
    

    工人阶级

    using System;
    using System.Collections.Generic;
    using System.Diagnostics;
    using System.IO;
    using System.Linq;
    using System.Net;
    using System.Net.Sockets;
    using System.Text;
    using System.Threading;
    using System.Threading.Tasks;
    
    namespace app
    {
        class Worker
        {
    
            public delegate void OnRetryDelegate(int id);
    
            public event OnRetryDelegate OnRetry;
    
            public delegate void OnRespnseDelegate(Worker sender, bool success);
    
            public event OnRespnseDelegate OnRespnse;
    
            public Worker()
            {
                Id = IdProvider.GetNewId();
                thread = new Thread(new ThreadStart(ExecuteAsync));
                thread.Start();
            }
    
            private readonly Thread thread;
            public string Number;
            public bool Idle { get; set; }
            public bool ShutDown { get; set; }
            public bool Started { get; set; }
            public int Id { get; private set; }
            public PostData { get; set; }
    
            public void Start(string postData)
            {
                PostData = postData;
                Idle = true;
                Started = true;
            }
    
            private void ExecuteAsync()
            {
                while (!ShutDown)
                {
                    Thread.Sleep(1500);
                    if (Idle)
                    {
                        Idle = false;
                        if (Number == "terminate")
                        {
                            ShutDown = true;
                            return;
                        }
    
                        try
                        {
                            var request = (HttpWebRequest) WebRequest.Create("https://example.com");
                            var data = Encoding.ASCII.GetBytes(postData);
                            Debug.Print("send:  " + postData);
                            request.Method = "POST";
                            request.ContentType = "application/x-www-form-urlencoded";
                            request.ContentLength = data.Length;
                            using (var stream = request.GetRequestStream())
                            {
                                stream.Write(data, 0, data.Length);
                            }
                            var response = (HttpWebResponse) request.GetResponse();
                            var responseString = new StreamReader(response.GetResponseStream()).ReadToEnd();
                            Debug.Print(responseString);
                            if (responseString.Contains("something"))
                                OnRespnse?.Invoke(this, true);
                        }
                        catch (Exception)
                        {
                            OnRetry?.Invoke(Id);
                        }
    
                        OnRespnse?.Invoke(this, false);
                    }
                }
            }
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-01-08
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多