2016-07-15 18 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

謝謝你。租戶很少從系統中刪除。比重新啓動服務少得多,所以我認爲我很安全。 –