[英]Maximum number of concurrent requests in Owin
我使用OWIN在控制台應用程序中自托管一個小型Web應用程序。
在到達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調用controller方法,該方法基本上將http請求異步地轉發到另一個API,即感興趣的主線是:
var response = await _httpClient.SendAsync(outgoingRequest);
但是,如果我嘗試這樣向API提交10個http請求(因為我想對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
我曾嘗試同時搜索Stackoverflow和Google,但似乎找不到任何有價值的東西。 例如,我找到了這個 ,但是在這里,開發人員在提交請求后讀取了請求,但我沒有這樣做。
以防萬一,您可以在此處包含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);
}
}
嘗試從各處刪除.ConfigureAwait(false)
,看看是否有幫助。
例如:
string requestContent = await request.Content.ReadAsStringAsync().ConfigureAwait(false);
UPD1:好的。 當您使用其他客戶端進行壓力測試時,請檢查此異常是否在服務器上發生。 例如這個 。 您不等待httpClient.SendAsync(...);
想法httpClient.SendAsync(...);
非常奇特。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.