2017-09-09 3 views
0

Je héberge moi-même une petite application web dans une application console en utilisant OWIN.Nombre maximal de requêtes simultanées dans Owin

Avant d'atteindre le ApiController il y a un middleware unique enregistré:

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 
     } 
    } 
} 

Ici Next.Invoke invoque la méthode du contrôleur, qui transmet essentiellement la requête HTTP à une autre API de manière asynchrone, à savoir la ligne d'intérêt principal est:

var response = await _httpClient.SendAsync(outgoingRequest); 

Cependant, si je tente de présenter 10 requêtes http à l'API comme celui-ci (et non qui les attend sur le but que je veux mettre preassure sur l'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); 
} 

puis immédiatement après soumettre 10 plus, je reçois l'exception suivante dans le bloc catch dans le HealthcheckMiddleware:

InvalidOperationException: Cette opération ne peut être effectuée après la réponse a été soumise.

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 

J'ai essayé la recherche à la fois Stackoverflow et Google, mais ne peut pas sembler trouver quelque chose de valeur. Par exemple j'ai trouvé this, mais ici le développeur lit la requête après l'avoir soumise, ce que je ne fais pas.

Juste au cas où il pourrait être intéressant la méthode POST complète dans le ApiController est inclus ici:

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); 
     } 
    } 

Répondre

0

Essayez de supprimer .ConfigureAwait(false) partout et voir si ça aide.

E.g. ici:

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

UPD1: Ok. Vérifiez si cette exception se produira sur le serveur lorsque vous utilisez un client différent pour le test de stress. Par exemple this one. Votre idée de ne pas attendre pour httpClient.SendAsync(...); est très particulière.

+0

Malheureusement, cela n'a fait aucune différence. Mais merci pour la suggestion! – SabrinaMH