Abbiamo SOA per la nostra soluzione. Stiamo usando .net framework 4.5.1, asp.net mvc 4.6, sql server, windows server e thinktecture identity server 3 (per chiamate webapi basate su token.)I metodi asincroni dell'applicazione Mvc sono sospesi
Struttura della soluzione simile;
La nostra applicazione di frontend in mvc parla con la nostra applicazione webapi tramite un wrapper httpClient. Ecco il codice generico del wrapper del client http;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading.Tasks;
namespace Cheetah.HttpClientWrapper
{
public class ResourceServerRestClient : IResourceServerRestClient
{
private readonly ITokenProvider _tokenProvider;
public ResourceServerRestClient(ITokenProvider tokenProvider)
{
_tokenProvider = tokenProvider;
}
public string BaseAddress { get; set; }
public Task<T> GetAsync<T>(string uri, string clientId)
{
return CheckAndInvokeAsync(async token =>
{
using (var client = new HttpClient())
{
ConfigurateHttpClient(client, token, clientId);
HttpResponseMessage response = await client.GetAsync(uri);
if (response.IsSuccessStatusCode)
{
return await response.Content.ReadAsAsync<T>();
}
var exception = new Exception($"Resource server returned an error. StatusCode : {response.StatusCode}");
exception.Data.Add("StatusCode", response.StatusCode);
throw exception;
}
});
}
private void ConfigurateHttpClient(HttpClient client, string bearerToken, string resourceServiceClientName)
{
if (!string.IsNullOrEmpty(resourceServiceClientName))
{
client.DefaultRequestHeaders.Add("CN", resourceServiceClientName);
}
if (string.IsNullOrEmpty(BaseAddress))
{
throw new Exception("BaseAddress is required!");
}
client.BaseAddress = new Uri(BaseAddress);
client.Timeout = new TimeSpan(0, 0, 0, 10);
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", bearerToken);
}
private async Task<T> CheckAndInvokeAsync<T>(Func<string, Task<T>> method)
{
try
{
string token = await _tokenProvider.IsTokenNullOrExpired();
if (!string.IsNullOrEmpty(token))
{
return await method(token);
}
var exception = new Exception();
exception.Data.Add("StatusCode", HttpStatusCode.Unauthorized);
throw exception;
}
catch (Exception ex)
{
if (ex.Data.Contains("StatusCode") && ((HttpStatusCode)ex.Data["StatusCode"]) == HttpStatusCode.Unauthorized)
{
string token = await _tokenProvider.GetTokenAsync();
if (!string.IsNullOrEmpty(token))
{
return await method(token);
}
}
throw;
}
}
public void ThrowResourceServerException(List<string> messages)
{
string message = messages.Aggregate((p, q) => q + " - " + p);
var exception = new Exception(message);
exception.Data.Add("ServiceOperationException", message);
throw exception;
}
}
}
Inoltre, a volte questo wrapper client HTTP usando con NitoAsync manager (chiamare i metodi asincrone come sync.), E qualche volta stiamo usando questo metodo generico direttamente con attendono - compito asincrono aspettare simili;
var result = await _resourceServerRestClient.GetAsync<ServiceOperation<DailyAgendaModel>>("dailyAgenda/" + id);
Così qui è il nostro problema:
Quando testiamo la nostra applicazione MVC con JMeter (per fare qualche genere-di prova di carico/10 thread per 1 sec), dopo un paio di minuti, mvc l'applicazione smette di funzionare [l'eccezione è l'attività annullata a causa del timeout] (forse solo 1-2 richieste di timeout) su questa riga: HttpResponseMessage response = await client.GetAsync(uri);
. Ma dopo quella richiesta, tutte le richieste saranno fallite come se fossero in fila. Quindi l'applicazione mvc è sospesa per 2-15 minuti (a caso) ma in quel momento posso inviare nuove richieste da postino a webapi. Sono ok, voglio dire, webapi sta rispondendo bene. Dopo un paio di minuti, il ritorno all'applicazione in mvc diventa normale.
Nota: Abbiamo il bilanciamento del carico per mvc-ui e webapi. Perché a volte riceviamo 120.000 richieste in un minuto in una giornata impegnativa. Ma dà lo stesso errore se non c'è un sistema di bilanciamento del carico di fronte a un'applicazione webapi o mvc. Quindi non è un problema con LB.
Nota2: Abbiamo provato a utilizzare RestSharp per le comunicazioni mvc-ui e webapi. Abbiamo lo stesso errore qui. Quando un reuqest sta fallendo, tutte le richieste saranno fallite di fila. Sembra che si tratti di un errore di rete, ma non possiamo trovare una prova per questo.
Riesci a vedere qualche errore sul mio wrapper httpClient? o meglio la domanda è;
Nella tua soluzione, in che modo la tua applicazione mvc comunica con l'applicazione webapi? Quali sono le migliori pratiche qui?
Update1: ci siamo trasferiti progetti .net 4.5.1 a 4.6.1. Lo stesso stallo è successo di nuovo. E poi abbiamo spostato temporaneamente tutti i codici sorgente del livello: "Business & Repository" come livello dll. Non ci sono webapi tra il livello di presentazione aziendale & ora. Blocco morto risolto. Stiamo ancora cercando perché i codici httpClientWrapper non funzionino correttamente quando abbiamo chiamato i metodi webapi dai nostri controller di applicazione web.
hai condiviso il codice di richiesta lato client. Ma il problema principale è wep api che non può rispondere normalmente. La tua richiesta sarà bloccata.Il lato Web api deve essere più veloce. È possibile aumentare il timeout. Non lo consiglio Forse puoi dormire la tua richiesta con Thread. Quelli non sono una buona soluzione. Si prega di condividere wep api side. Forse possiamo aumentare performans –
@ SercanTimoçin grazie per la vostra risposta. Howerer webapi è la migliore API che abbiamo scritto, nei nostri test di carico; il tempo di risposta massimo è <500ms. Quindi non pensiamo che sia il faulth del metodo web api. –
La soluzione migliore è eseguire un dump completo della memoria quando l'applicazione si blocca/inizia a scadere. Puoi usare qualcosa come [WinDbg] (https://msdn.microsoft.com/en-us/windows/hardware/hh852365.aspx) per poi eseguire un '! Analize' o [Debug Diag] (https: // www .microsoft.com/it/us/download/details.aspx? id = 49924) per vedere cosa sta succedendo. Potrebbe essere deadlock o risorse non rilasciate o chissà cosa, ma nessuno può dire senza vedere il codice dell'applicazione e osservare come si comporta. – Igor