Vraag Wat is in asp.net-mvc de juiste manier om dure bewerkingen uit te voeren zonder andere gebruikers te beïnvloeden?


Ik stelde deze vraag ongeveer 5 jaar geleden rond om dure operaties "af te lossen" waar de gebruikers niet op hoeven te wachten (zoals audioneren, enz.), zodat ze sneller een antwoord krijgen aan de voorkant.

Ik heb nu een verwante maar andere vraag. Op mijn asp.net-mvc heb ik een aantal rapportagepagina's gemaakt waar je Excel-rapporten kunt genereren (i gebruik EPPlus) en powerpoint-rapporten (ik gebruik aspose.slides). Hier is een voorbeeld van de actie van de controller:

    public ActionResult GenerateExcelReport(FilterParams args)
    {
        byte[] results = GenerateLargeExcelReportThatTake30Seconds(args);
        return File(results, @"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml", "MyReport.xlsx");
    }

De functionaliteit werkt prima, maar ik probeer te achterhalen of deze dure bewerkingen (sommige rapporten kunnen tot 30 seconden duren om terug te keren) een impact hebben anders gebruikers. In de vorige vraag had ik een dure bewerking die de gebruiker DIDN "T moet wachten, maar in dit geval moet hij wachten omdat het een syncronoous activiteit is (klik op Rapport genereren en de verwachting is dat gebruikers een rapport krijgen als het klaar is )

In dit geval kan het me niet schelen dat de hoofdgebruiker 30 seconden moet wachten maar ik wil alleen zeker weten dat ik geen negatieve invloed heb op andere gebruikers vanwege deze dure bewerking, het genereren van bestanden, enz

Bestaat er hier een best practice in asp.net-mvc voor dit gebruik?


18
2017-12-08 10:41


oorsprong


antwoorden:


Je kunt een combinatie van Hangfire en SignalR proberen. Gebruik Hangfire om een ​​achtergrondtaak te starten en het http-verzoek af te staan. En als het genereren van het rapport is voltooid, gebruikt u SignalR om een ​​pushmelding te genereren.

SignalR-melding van server naar client

Alternatieve optie is om een ​​polling-mechanisme aan de kant van de klant te implementeren. Stuur een ajax-oproep om een ​​hangfire-taak in te schakelen om het rapport te genereren. En begin met het afvragen van sommige api met een andere ajax-oproep die de status biedt en zodra het rapport gereed is, haalt u het op. Ik geef de voorkeur aan SignalR in plaats van polling.

Als de verwerking van het rapport invloed heeft op de prestaties op de webserver, laadt u die verwerking over naar een andere server. U kunt berichtuitwisseling gebruiken (ActiveMQ of RabbitMQ of een ander framework naar keuze) of een api-oproep uitvoeren om het genereren van rapporten op een andere server te starten en vervolgens opnieuw berichten of een terugmelding gebruiken om de voltooiing van het genereren van rapporten terug te melden bij de webserver, ten slotte SignalR om de klant op de hoogte te stellen. Hierdoor kan de webserver sneller reageren.

BIJWERKEN Met betrekking tot jouw vraag

Bestaat hier een best practice in asp.net-mvc voor dit gebruik

U moet uw toepassing overuren monitoren. Monitor zowel client- als serverkant. Er zijn weinig tools waarop u kunt vertrouwen, zoals newrelic, app-dynamica. Ik heb newrelic gebruikt en het heeft functies om problemen zowel bij de client-browser als bij de server te volgen. De namen van het product zijn "NewRelic Browser" en "NewRelic Server". Ik weet zeker dat er andere tools zijn die vergelijkbare informatie zullen vastleggen.

Analyseer de metriek overuren en als u afwijkingen ziet, neem dan gepaste maatregelen. Als u CPU- en geheugenpieken aan de serverzijde waarneemt, probeert u statistieken op te slaan aan de clientzijde rond dezelfde tijdspanne. Aan de kant van de klant, als u time-outproblemen opmerkt, kunnen er verbindingsfouten optreden waardoor gebruikers van uw toepassing geen verbinding kunnen maken met uw app terwijl de server zwaar aan het tillen is. Probeer vervolgens knelpunten aan de serverzijde te identificeren. Als er niet genoeg ruimte is om de code af te stemmen, ga dan naar een aantal oefeningen voor servercapaciteitplanning en zoek uit hoe u uw hardware verder kunt schalen of de achtergrondtaken van de webservers kunt verplaatsen om de belasting te verminderen. Alleen het vastleggen van statistieken met behulp van deze tools is misschien niet voldoende, het kan zijn dat u uw toepassing moet instrumenteren (vastleggen) om aanvullende meetwaarden vast te leggen om de gezondheid van de toepassing goed te kunnen volgen.

Hier u kunt wat informatie vinden over capaciteitsplanning voor .net-applicaties van Microsoft.

-Vinod.


6
2017-12-08 11:16



Dit zijn allemaal geweldige ideeën over hoe het werk uit de verzoek / responscyclus kan worden verplaatst. Maar ik denk dat @leora eenvoudig wil weten of een langlopend verzoek andere gebruikers van een asp.net-applicatie nadelig zal beïnvloeden.

Het antwoord is nee. asp.net is multi-threaded. Elke aanvraag wordt afgehandeld door een afzonderlijke werkthread.


5
2017-12-22 05:57



Over het algemeen kan het als een goede gewoonte worden beschouwd om langlopende taken op de achtergrond uit te voeren en een soort van kennisgeving aan de gebruiker te geven wanneer de klus is geklaard. Zoals u waarschijnlijk weet, is de uitvoeringstijd van het webverzoek beperkt tot 90 seconden, dus als uw langlopende taak dit zou kunnen overschrijden, hebt u geen andere keuze dan een andere thread / proces uit te voeren. Als u .net 4.5.2 gebruikt, kunt u gebruiken HostingEnvironment.QueueBackgroundWorkItem voor het uitvoeren van langlopende taken op de achtergrond en gebruik SignalR om de gebruiker op de hoogte te stellen wanneer de taak is voltooid, de uitvoering. In het geval dat u een bestand aan het genereren bent, kunt u het opslaan op de server met een uniek ID en een link naar de gebruiker sturen om het te downloaden. U kunt dit bestand later verwijderen (bijvoorbeeld met een aantal Windows-services).

Zoals door anderen wordt vermeld, zijn er enkele meer geavanceerde achtergrond taak lopers zoals Hangfire, Quartz.Net en anderen, maar het algemene concept is hetzelfde - voer de taak in backround uit en stel de gebruiker op de hoogte als deze klaar is. Hier is wat leuk artikel over verschillende oprions om achtergrondtaken uit te voeren.


2
2017-12-08 11:16



Je moet gebruiken async en wachten op C #.

Op basis van uw vraag dacht ik dat u zich alleen zorgen maakt over het feit dat het verzoek meer middelen kan innen dan zou moeten, in plaats van met schaalbaarheid. Als dat het geval is, moet u de asynchroonloop van uw controller uitvoeren, evenals alle bewerkingen die u uitvoert, zolang ze betrekking hebben op oproepen die threads blokkeren. bijv. als uw aanvragen via draden of I / O-bewerkingen gaan, blokkeren ze de thread zonder async (technisch gezien wel, want u wacht op het antwoord voordat u doorgaat). Met async zijn die threads beschikbaar (in afwachting van het antwoord) en kunnen ze mogelijk andere verzoeken van andere gebruikers dienen.

Ik ging ervan uit dat je niet ronddoolde om de verzoeken te schalen. Als dat zo is, laat het me weten, en ik kan daar ook details over geven (te veel om te schrijven tenzij het nodig is).


2
2017-12-19 20:03



Ik geloof dat een tool / bibliotheek zoals Hangfire is wat je zoekt. Ten eerste kunt u een taakrun op een achtergrondthread opgeven (in dezelfde toepassing / hetzelfde proces). Met behulp van verschillende technieken, zoals SignalR maakt real-time front-end melding mogelijk.

Iets dat ik na het gebruik van Hangfire bijna een jaar heb gemaakt, was echter het splitsen van onze taakverwerking (en implementatie) naar een andere server met deze documentatie. Ik gebruik een interne ASP.NET MVC-toepassing om taken op een andere server te verwerken. Het enige prestatieknelpunt is dan als beide servers hetzelfde gegevensarchief gebruiken (bijvoorbeeld een database). Als u de database vergrendelt, is de enige manier om de database te vergrendelen, ongeacht de gebruikte methode.

Ik gebruik interfaces om taken te activeren, opgeslagen in een gemeenschappelijke bibliotheek:

public interface IMyJob
{
    MyJobResult Execute( MyJobSettings settings );
}

En, de trigger, gevonden in de front-endapplicatie:

//tell the job to run
var settings =  new MyJobSettings();
_backgroundJobClient.Enqueue<IMyJob>( c => c.Execute( settings ) );

Vervolgens schrijf ik op mijn achtergrondserver de implementatie (en haak het in de Autofac IOC-container Ik gebruik):

public class MyJob : IMyJob
{
    protected override MyJobResult Running( MyJobSettings settings )
    {
         //do stuff here
    }
}

Ik heb er niet te veel aan gedaan om te proberen SignalR over de twee servers te laten werken, aangezien ik nog niet in die specifieke use-case is beland, maar het is theoretisch mogelijk, stel ik me voor.


1
2017-12-19 19:58



U moet uw toepassingsgebruikers controleren om te weten of andere gebruikers worden getroffen, bijvoorbeeld door reactietijden op te nemen

Als u merkt dat dit andere gebruikers beïnvloedt, moet u de taak uitvoeren in een ander proces, mogelijk op een andere computer. U kunt de bibliotheek gebruiken Hangfire om dit te behalen.


0
2017-12-08 10:54



Met dat antwoord kunt u een taak met lage prioriteit declareren

lagere prioriteit van Task.Factory.StartNieuwe thread

 public ActionResult GenerateExcelReport(FilterParams args)
 {
     byte[] result = null;
     Task.Factory.StartNew(() =>
     {
        result =  GenerateLargeExcelReportThatTake30Seconds(args);
     }, null, TaskCreationOptions.None, PriorityScheduler.BelowNormal)
      .Wait();

     return File(result, @"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml", "MyReport.xlsx");
 }

0
2017-12-19 19:10



Wacht een wachtrij op de taken in een tabel en laat een achtergrondprocesopvraag maken met die tabel om te bepalen welke Zeer grote taak moet worden uitgevoerd. Uw webclient zou dan de server moeten pollen om te bepalen wanneer de taak voltooid is (mogelijk door een vlag in de database te controleren, maar er zijn andere methoden.) Dit garandeert dat u niet meer dan één (of hoe veel ook) zult hebben beslissen is gepast) van deze dure processen die tegelijkertijd worden uitgevoerd.

Hangfire en SignalR kunnen u hierbij helpen, maar een wachtrijmechanisme is echt nodig om grote verstoringen te voorkomen wanneer bijvoorbeeld vijf gebruikers hetzelfde proces tegelijkertijd aanvragen. De benaderingen vermeldden dat het afvuren van nieuwe threads of achtergrondprocessen geen mechanisme lijkt te bieden voor het minimaliseren van processor / geheugenconsumptie om te voorkomen dat andere gebruikers worden verstoord vanwege het gebruik van te veel bronnen.


0
2017-12-20 01:37