2017-09-09 98 views
0

我使用OWIN在控制檯應用程序中自主託管小型Web應用程序。Owin中的最大併發請求數

之前到達ApiController有登記的單一的中間件:

public class HealthcheckMiddleware : OwinMiddleware 
{ 
    private readonly string DeepHealthEndpointPath = "/monitoring/deep"; 
    private readonly string ShallowHealthEndpointPath = "/monitoring/shallow"; 

    public HealthcheckMiddleware(OwinMiddleware next) 
     : base(next) 
    { 
    } 

    public async override Task Invoke(IOwinContext context) 
    { 
     try 
     { 
      string requestPath = context.Request.Path.Value.TrimEnd('/'); 
      if (requestPath.Equals(ShallowHealthEndpointPath, StringComparison.InvariantCultureIgnoreCase) 
       || requestPath.Equals(DeepHealthEndpointPath, StringComparison.InvariantCultureIgnoreCase)) 
      { 
       context.Response.StatusCode = (int) HttpStatusCode.OK; 
      } 
      else 
      { 
       await Next.Invoke(context); 
      } 
     } 
     catch (Exception ex) 
     { 
      // This try-catch block is inserted for debugging 
     } 
    } 
} 

這裏Next.Invoke調用控制器的方法,基本上異步轉發http請求到另一個API,即感興趣的主線是:

var response = await _httpClient.SendAsync(outgoingRequest); 

但是,如果我試圖提交10個HTTP請求到這樣的API(不是等待他們的目的,我想提出preassure對API)

for (int i = 0; i < 10; i++) 
{ 
    var httpRequestMessage = new HttpRequestMessage(HttpMethod.Post, "http://localhost:5558/forwarder"); 
    httpRequestMessage.Content = new StringContent(JsonConvert.SerializeObject(message), Encoding.UTF8, "application/json"); 
    httpClient.SendAsync(httpRequestMessage); 
} 

,然後立即提交後10多,然後我得到在HealthcheckMiddleware catch塊以下異常:

InvalidOperationException異常:已提交響應後無法執行此操作。

堆棧跟蹤:

at System.Net.HttpListenerResponse.set_ContentLength64(Int64 value) 
at Microsoft.Owin.Host.HttpListener.RequestProcessing.ResponseHeadersDictionary.Set(String header, String value) 
at Microsoft.Owin.Host.HttpListener.RequestProcessing.HeadersDictionaryBase.Set(String key, String[] value) 
at Microsoft.Owin.Host.HttpListener.RequestProcessing.HeadersDictionaryBase.set_Item(String key, String[] value) 
at Microsoft.Owin.HeaderDictionary.System.Collections.Generic.IDictionary<System.String,System.String[]>.set_Item(String key, String[] value) 
at System.Web.Http.Owin.HttpMessageHandlerAdapter.SetHeadersForEmptyResponse(IDictionary`2 headers) 
at System.Web.Http.Owin.HttpMessageHandlerAdapter.SendResponseMessageAsync(HttpRequestMessage request, HttpResponseMessage response, IOwinResponse owinResponse, CancellationToken cancellationToken) 
at System.Web.Http.Owin.HttpMessageHandlerAdapter.<InvokeCore>d__0.MoveNext() 
--- End of stack trace from previous location where exception was thrown --- 
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) 
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) 
at System.Runtime.CompilerServices.TaskAwaiter.GetResult() 
at DataRelay.NonGuaranteedDataForwarder.HealthcheckMiddleware.<Invoke>d__3.MoveNext() in C:\_code\DataRelay.NonGuaranteedDataForwarder\HealthcheckMiddleware.cs:line 30 

我試圖尋找二者#1和谷歌,但似乎無法找到任何有價值的東西。例如,我發現this,但是在這裏開發人員在提交請求後讀取請求,我不這樣做。

以防萬一它可能會感興趣的ApiController全POST方法在這裏包括:

public async Task<HttpResponseMessage> Post(HttpRequestMessage request) 
    { 
     try 
     { 
      MetricCollector.RecordIncomingRecommendation(); 
      using (MetricCollector.TimeForwardingOfRequest()) 
      { 
       string requestContent = await request.Content.ReadAsStringAsync().ConfigureAwait(false); 
       var data = JObject.Parse(requestContent); 
       string payloadType = data.SelectToken("Headers.PayloadType").ToString(); 
       Log.Logger.Debug("Received message containing {PayloadType}", payloadType); 

       var consumersForPayloadType = _consumers.Where(x => x.DataTypes.Contains(payloadType)).ToList(); 
       if (consumersForPayloadType.Any()) 
       { 
        Log.Logger.Debug("{NumberOfConsumers} interested in {PayloadType}", 
         consumersForPayloadType.Count, 
         payloadType); 
       } 
       else 
       { 
        Log.Logger.Warning("No consumers are interested in {PayloadType}", payloadType); 
       } 

       foreach (var consumer in consumersForPayloadType) 
       { 
        try 
        { 
         var outgoingRequest = new HttpRequestMessage(HttpMethod.Post, consumer.Endpoint); 
         outgoingRequest.Content = new StringContent(requestContent, Encoding.UTF8, 
          "application/json"); 

         foreach (var header in request.Headers) 
         { 
          if (IsCustomHeader(header, _customHeaders)) 
           outgoingRequest.Headers.Add(header.Key, header.Value); 
         } 

         if (!string.IsNullOrWhiteSpace(consumer.ApiKey)) 
         { 
          request.Headers.Add("Authorization", "ApiKey " + consumer.ApiKey); 
         } 

         var response = await _httpClient.SendAsync(outgoingRequest); 
         if (!response.IsSuccessStatusCode) 
         { 
          Log.Logger.ForContext("HttpStatusCode", response.StatusCode.ToString()) 
           .Error("Failed to forward message containing {PayloadType} to {ConsumerEndpoint}", 
            payloadType, consumer.Endpoint); 
         } 
        } 
        catch (Exception ex) 
        { 
         MetricCollector.RecordException(ex); 
         Log.Logger.Error(ex, 
          "Failed to forward message containing {PayloadType} to {ConsumerEndpoint}", payloadType, 
          consumer.Endpoint); 
        } 
       } 

       return request.CreateResponse(HttpStatusCode.OK); 
      } 
     } 
     catch (Exception ex) 
     { 
      return Request.CreateErrorResponse(HttpStatusCode.ServiceUnavailable, ex); 
     } 
    } 

回答

0

嘗試取出.ConfigureAwait(false)無處不在,看看是否有幫助。

E.g.在這裏:

string requestContent = await request.Content.ReadAsStringAsync().ConfigureAwait(false); 

UPD1:好的。當您使用不同的客戶端進行壓力測試時,請檢查服務器是否會發生此異常。例如this one。 您不想等待httpClient.SendAsync(...);的想法非常奇特。

+0

不幸的是,它沒有任何區別。但是,謝謝你的建議! – SabrinaMH