简体   繁体   English

Owin中的最大并发请求数

[英]Maximum number of concurrent requests in Owin

I self-host a small web application in a console application using OWIN. 我使用OWIN在控制台应用程序中自托管一个小型Web应用程序。

Before reaching the ApiController there's a single middleware registered: 在到达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
        }
    }
}

Here Next.Invoke invokes the controller method, which basically forwards the http request to another API asynchronously, ie the main line of interest is: 在此Next.Invoke调用controller方法,该方法基本上将http请求异步地转发到另一个API,即感兴趣的主线是:

var response = await _httpClient.SendAsync(outgoingRequest);

However, if I try to submit 10 http requests to the API like this (not awaiting them on purpose as I want to put preassure on the API) 但是,如果我尝试这样向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);
}

and then immediately afterwards submit 10 more, then I get the following exception in the catch block in the HealthcheckMiddleware: 然后再提交10个,然后在HealthcheckMiddleware的catch块中得到以下异常:

InvalidOperationException: This operation cannot be performed after the response has been submitted. InvalidOperationException:提交响应后无法执行此操作。

Stacktrace: 堆栈跟踪:

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

I've tried searching both Stackoverflow and Google, but cannot seem to find anything of value. 我曾尝试同时搜索Stackoverflow和Google,但似乎找不到任何有价值的东西。 For instance I found this , but here the developer reads the request after submitting it, which I don't do. 例如,我找到了这个 ,但是在这里,开发人员在提交请求后读取了请求,但我没有这样做。

Just in case it could be of interest the full POST method in the ApiController is included here: 以防万一,您可以在此处包含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);
        }
    }

Try removing .ConfigureAwait(false) everywhere and see if it helps. 尝试从各处删除.ConfigureAwait(false) ,看看是否有帮助。

Eg here: 例如:

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

UPD1: Ok. UPD1:好的。 Check if this exception will occur on server when you use different client for stress testing. 当您使用其他客户端进行压力测试时,请检查此异常是否在服务器上发生。 For instance this one . 例如这个 Your idea of not awaiting for httpClient.SendAsync(...); 您不等待httpClient.SendAsync(...);想法httpClient.SendAsync(...); is very peculiar. 非常奇特。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM