2016-07-15 49 views
0

我正在编写一个使用HttpClient访问API的类,并且我想限制可以对此类中的某个函数执行的并发调用的数量。窍门是虽然限制是每个租户,并且多个租户可能一次使用他们自己的类的实例。通过一些变量来限制HttpClient请求

我的Tenant类只是一个只读上下文信息的容器。

public class Tenant 
{ 
    public string Name { get; } 
    public string ApiKey { get; } 
} 

这里的ApiClient:

public class ApiClient 
{ 
    private readonly Tenant tenant; 

    public ApiClient(Tenant tenant) 
    { 
     this.tenant = tenant; 
    } 

    public async Task<string> DoSomething() 
    { 
     var response = await this.SendCoreAsync(); 
     return response.ToString(); 
    } 

    private Task<XElement> SendCore() 
    { 
     using (var httpClient = new HttpClient()) 
     { 
      var httpRequest = this.BuildHttpRequest(); 
      var httpResponse = await httpClient.SendAsync(httpRequest); 
      return XElement.Parse(await httpResponse.Content.ReadAsStringAsync()); 
     } 
    } 
} 

我想要做的就是油门SendCore方法,它限制了两个并发请求每个租户。我已阅读使用TPLSemaphoreSlim进行基本调节的建议(例如:Throttling asynchronous tasks),但我不清楚如何补充租户的进一步复杂性。

感谢您的建议。

UPDATE

我已经尝试使用一组包含在ConcurrentDictionarySemaphoreSlim对象(每个租户一个)的。这似乎有效,但我不确定这是否理想。新代码是:

public class ApiClient 
{ 
    private static readonly ConcurrentDictionary<string, SemaphoreSlim> Semaphores = new ConcurrentDictionary<string, SemaphoreSlim>(); 
    private readonly Tenant tenant; 
    private readonly SemaphoreSlim semaphore; 

    public ApiClient(Tenant tenant) 
    { 
     this.tenant = tenant; 
     this.semaphore = Semaphores.GetOrAdd(this.tenant.Name, k => new SemaphoreSlim(2)); 
    } 

    public async Task<string> DoSomething() 
    { 
     var response = await this.SendCoreAsync); 
     return response.ToString(); 
    } 

    private Task<XElement> SendCore() 
    { 
     await this.semaphore.WaitAsync(); 
     try 
     { 
      using (var httpClient = new HttpClient()) 
      { 
       var httpRequest = this.BuildHttpRequest(); 
       var httpResponse = await httpClient.SendAsync(httpRequest); 
       return XElement.Parse(await httpResponse.Content.ReadAsStringAsync()); 
      } 
     } 
     finally 
     { 
      this.semaphore.Release(); 
     } 
    } 
} 
+0

'Tenant'究竟是什么?它是来自某个图书馆(哪一个?)或您的自定义班级的课程?为了这个目的修改它是否有意义?另外,一个'Tenant'可以有多个'ApiClient'吗? – svick

+0

租户只是一个小的上下文类,它包含租户的名称和API客户端使用的一些连接信息,如用户名/密码。我正在使用ASP.NET WebJobs SDK,并且在处理服务总线消息时简单地注入Tenant。您可以将租户对象视为只读。 –

+0

我已经用我提出的信号量方法更新了这个问题。 –

回答

0

您的SemaphoreSlim方法似乎对我来说最合理。

一个潜在的问题是,如果Tenant可以在应用程序的整个生命周期中来回移动,那么即使对于不存在的Tenant s,您也会保留信号量。

一个解决方案是使用ConditionalWeakTable<Tenant, SemaphoreSlim>而不是你的ConcurrentDictionary,它确保它的密钥可以被垃圾收集,当它们是时,它释放的价值。

+0

谢谢你。租户很少从系统中删除。比重新启动服务少得多,所以我认为我很安全。 –