W aplikacji ASP.Net użytkownik klika przycisk na stronie internetowej, a następnie tworzy instancję obiektu na serwerze za pośrednictwem modułu obsługi zdarzeń i wywołuje metodę na obiekcie. Metoda przechodzi do systemu zewnętrznego w celu wykonania pewnych czynności i może to chwilę potrwać. Chciałbym więc uruchomić to wywołanie metody w innym wątku, abym mógł zwrócić kontrolę użytkownikowi z komunikatem „Twoje żądanie zostało przesłane”. Jestem dość szczęśliwy, że mogę to zrobić jako odpal i zapomnij, chociaż byłoby jeszcze przyjemniej, gdyby użytkownik mógł nadal odpytywać obiekt pod kątem statusu.
Nie wiem, czy IIS zezwala na działanie mojego wątku, nawet po wygaśnięciu sesji użytkownika. Wyobraź sobie, że użytkownik uruchamia zdarzenie, a my tworzymy instancję obiektu na serwerze i uruchamiamy metodę w nowym wątku. Użytkownik jest zadowolony z komunikatu „Twoja prośba została przesłana” i zamyka przeglądarkę. W końcu ta sesja użytkownika wygaśnie w usługach IIS, ale wątek może nadal działać, wykonując pracę. Czy usługi IIS pozwolą na kontynuowanie działania wątku, czy też zabiją go i pozbędą się obiektu po wygaśnięciu sesji użytkownika?
EDYCJA: Z odpowiedzi i komentarzy wynika, że najlepszym sposobem na to jest przeniesienie długotrwałego przetwarzania poza usługi IIS. Oprócz wszystkiego innego dotyczy to problemu recyklingu domeny aplikacji. W praktyce potrzebuję uruchomić wersję 1 w ograniczonym czasie i muszę pracować w istniejącym frameworku, więc chciałbym uniknąć warstwy usług, stąd chęć po prostu odpalenia wątku wewnątrz IIS. W praktyce „długotrwałe” to tylko kilka minut, a współbieżność na stronie będzie niska, więc powinno być w porządku. Ale następna wersja z pewnością będzie wymagała podzielenia na osobną warstwę usług.
Odpowiedzi:
Możesz osiągnąć to, co chcesz, ale zazwyczaj jest to zły pomysł. Niektóre blogi ASP.NET i silniki CMS stosują to podejście, ponieważ chcą być instalowane we współużytkowanym systemie hostingu i nie są zależne od usługi systemu Windows, która musi zostać zainstalowana. Zwykle uruchamiają długo działający wątek w Global.asax podczas uruchamiania aplikacji i powodują, że ten wątek przetwarza zadania w kolejce.
Oprócz ograniczenia zasobów dostępnych dla usług IIS / ASP.NET w celu przetwarzania żądań, występują również problemy z zabijaniem wątku, gdy domena AppDomain jest odtwarzana, a następnie musisz radzić sobie z trwałością zadania podczas lotu, ponieważ a także rozpoczęcie pracy z powrotem po przywróceniu AppDomain.
Należy pamiętać, że w wielu przypadkach AppDomain jest automatycznie odtwarzana w domyślnych odstępach czasu, a także po zaktualizowaniu pliku web.config itp.
Jeśli w dowolnym momencie możesz poradzić sobie z trwałością i transakcyjnymi aspektami zabicia wątku, możesz obejść recykling AppDomain, korzystając z zewnętrznego procesu, który wysyła żądanie w Twojej witrynie w określonych odstępach czasu - tak, że jeśli witryna zostanie poddana recyklingowi, gwarantują automatyczne ponowne uruchomienie kopii zapasowej w ciągu X minut.
Ponownie, jest to zazwyczaj zły pomysł.
EDYCJA: Oto kilka przykładów tej techniki w akcji:
Community Server: korzystanie z usług systemu Windows w porównaniu z wątkiem w tle do uruchamiania kodu w zaplanowanych odstępach czasu Tworzenie wątku w tle przy pierwszym uruchomieniu witryny
EDYCJA (z odległej przyszłości) - Obecnie używałbym Hangfire .
źródło
HostingEnvironment.RegisterObject
).QueueBackgroundWorkItem
do łatwego rejestrowania zadań w tle, możesz ponownie zaktualizować swoją odpowiedź.Nie zgadzam się z zaakceptowaną odpowiedzią.
Korzystanie z wątku w tle (lub zadania uruchomionego za pomocą
Task.Factory.StartNew
) jest w porządku w ASP.NET. Podobnie jak w przypadku wszystkich środowisk hostingowych, możesz chcieć zrozumieć i współpracować z obiektami zarządzającymi zamykaniem.W ASP.NET można zarejestrować pracę wymagającą bezpiecznego zatrzymania podczas zamykania przy użyciu
HostingEnvironment.RegisterObject
metody. Zobacz ten artykuł i komentarze do dyskusji.(Jak zauważył Gerard w swoim komentarzu, istnieje teraz również
HostingEnvironment.QueueBackgroundWorkItem
wezwanieRegisterObject
do zarejestrowania harmonogramu dla elementu w tle do pracy. Ogólnie nowa metoda jest ładniejsza, ponieważ jest oparta na zadaniach).Jeśli chodzi o ogólny temat, o którym często słyszysz, że jest to zły pomysł, rozważ alternatywę polegającą na wdrożeniu usługi systemu Windows (lub innego rodzaju aplikacji pozaprocesowej):
Należy również zauważyć, że niektóre zaawansowane scenariusze mogą nawet wymagać, aby wątek w tle działał w tej samej przestrzeni adresowej, co żądania. Fakt, że ASP.NET może to zrobić, uważam za wielką zaletę, która stała się możliwa dzięki .NET.
źródło
Nie chcesz używać wątku z puli wątków usług IIS do tego zadania, ponieważ spowoduje to, że ten wątek nie będzie mógł przetwarzać przyszłych żądań. Możesz zajrzeć do stron asynchronicznych w ASP.NET 2.0 , ale to też nie byłaby właściwa odpowiedź. Zamiast tego wydaje się, że warto byłoby przyjrzeć się usłudze Microsoft Message Queuing . Zasadniczo należy dodać szczegóły zadania do kolejki i inny proces w tle (prawdopodobnie usługa systemu Windows) byłby odpowiedzialny za wykonanie tego zadania. Najważniejsze jest jednak to, że proces w tle jest całkowicie odizolowany od usług IIS.
źródło
Sugerowałbym użycie HangFire do takich wymagań. Jest to ładny silnik typu „fire and zapomnij”, który działa w tle, obsługuje inną architekturę, jest niezawodny, ponieważ jest wspierany przez pamięć trwałą.
źródło
Tutaj jest dobry wątek i przykładowy kod: http://forums.asp.net/t/1534903.aspx?PageIndex=2
Bawiłem się nawet pomysłem wywołania z wątku strony utrzymującej życie w mojej witrynie, aby pomóc utrzymać pulę aplikacji przy życiu. Pamiętaj, że jeśli używasz tej metody, potrzebujesz naprawdę dobrej obsługi odzyskiwania, ponieważ aplikacja może w dowolnym momencie zostać ponownie użyta. Jak wielu wspomniało, nie jest to właściwe podejście, jeśli masz dostęp do innych opcji usług, ale w przypadku hostingu współdzielonego może to być jedyna opcja.
Aby pomóc w utrzymaniu puli aplikacji przy życiu, możesz wysłać żądanie do własnej witryny podczas przetwarzania wątku. Może to pomóc w utrzymaniu puli aplikacji przy życiu, jeśli proces trwa długo.
string tempStr = GetUrlPageSource("http://www.mysite.com/keepalive.aspx"); public static string GetUrlPageSource(string url) { string returnString = ""; try { Uri uri = new Uri(url); if (uri.Scheme == Uri.UriSchemeHttp) { HttpWebRequest req = (HttpWebRequest)WebRequest.Create(uri); CookieContainer cookieJar = new CookieContainer(); req.CookieContainer = cookieJar; //set the request timeout to 60 seconds req.Timeout = 60000; req.UserAgent = "MyAgent"; //we do not want to request a persistent connection req.KeepAlive = false; HttpWebResponse resp = (HttpWebResponse)req.GetResponse(); Stream stream = resp.GetResponseStream(); StreamReader sr = new StreamReader(stream); returnString = sr.ReadToEnd(); sr.Close(); stream.Close(); resp.Close(); } } catch { returnString = ""; } return returnString; }
źródło
Zaczęliśmy tą ścieżkę i faktycznie działało dobrze, gdy nasza aplikacja była na jednym serwerze. Kiedy chcieliśmy skalować w poziomie do wielu komputerów (lub używać wielu w3wp w sieci Web Garen), musieliśmy ponownie ocenić i przyjrzeć się, jak zarządzać kolejką roboczą, obsługą błędów, ponownymi próbami i trudnym problemem prawidłowego blokowania, aby zapewnić tylko jedną serwer przejmuje następny element.
... zdaliśmy sobie sprawę, że nie zajmujemy się pisaniem silników przetwarzania w tle, więc szukaliśmy istniejących rozwiązań i wylądowaliśmy przy użyciu niesamowitego projektu OSS Hangfire
Sergey Odinokov stworzył prawdziwy klejnot, od którego naprawdę łatwo zacząć, i który pozwala na zmianę zaplecza, w jaki sposób praca jest utrwalana i umieszczana w kolejce. Hangfire używa wątków w tle, ale utrzymuje zadania, obsługuje ponowienia i zapewnia wgląd w kolejkę roboczą. Tak więc prace związane z ogniem hangarowym są solidne i przetrwają wszystkie kaprysy związane z recyklingiem aplikacji itp.
Jego podstawowa konfiguracja wykorzystuje serwer sql jako magazyn, ale można zamienić go na Redis lub MSMQ, gdy nadejdzie czas na skalowanie w górę. Posiada również doskonały interfejs użytkownika do wizualizacji wszystkich zadań i ich statusu, a także umożliwia ponowne kolejkowanie zadań.
Chodzi mi o to, że chociaż w wątku w tle można robić to, co chcesz, to jest dużo pracy, aby uczynić go skalowalnym i solidnym. Jest to dobre dla prostych obciążeń, ale kiedy sprawy stają się bardziej złożone, wolę używać specjalnie zbudowanej biblioteki, zamiast wykonywać ten wysiłek.
Aby uzyskać więcej informacji na temat dostępnych opcji, zapoznaj się z blogiem Scotta Hanselmana, w którym opisano kilka opcji obsługi zadań w tle w asp.net. (Dał hangfire świetną recenzję)
Jak wspomina John, warto przeczytać blog Phila Haacka o tym, dlaczego to podejście jest problematyczne i jak wdzięcznie przerwać pracę nad wątkiem, gdy domena aplikacji jest wyładowana.
źródło
Czy możesz utworzyć usługę systemu Windows, aby wykonać to zadanie? Następnie użyj zdalnej usługi .NET z serwera sieci Web, aby wywołać usługę systemu Windows w celu wykonania akcji? Jeśli tak jest, to właśnie bym zrobił.
To wyeliminowałoby potrzebę korzystania z usług IIS i ograniczyłoby część jego mocy obliczeniowej.
Jeśli nie, zmusiłbym użytkownika, aby siedział tam, gdy proces jest zakończony. W ten sposób upewnisz się, że został on ukończony i nie został zabity przez usługi IIS.
źródło
Wydaje się, że istnieje jeden obsługiwany sposób hostowania długotrwałych prac w usługach IIS. Wydaje się, że usługi przepływu pracy zostały zaprojektowane do tego celu, szczególnie w połączeniu z oprogramowaniem Windows Server AppFabric . Projekt pozwala na ponowne wykorzystanie puli aplikacji, wspierając automatyczne utrzymywanie i wznawianie długotrwałej pracy.
źródło
Możesz uruchamiać zadania w tle i zostaną ukończone nawet po zakończeniu żądania. Nie pozwól, aby nieprzechwycony wyjątek został wyrzucony . Zwykle chcesz zawsze zgłaszać swoje wyjątki. Jeśli wyjątek zostanie zgłoszony w nowym wątku, spowoduje to awarię procesu roboczego usług IIS - w3wp.exe , ponieważ nie znajdujesz się już w kontekście żądania. To również spowoduje zabicie wszelkich innych uruchomionych zadań w tle, oprócz sesji wspieranych pamięcią w procesie, jeśli ich używasz. Byłoby to trudne do zdiagnozowania, dlatego praktyka jest odradzana.
źródło
Po prostu utwórz zastępczy proces, aby uruchomić zadania asynchroniczne; nie musi to być usługa systemu Windows (chociaż w większości przypadków jest to bardziej optymalne podejście. MSMQ to zdecydowanie za dużo.
źródło