2013-02-05 11 views
15

Mam webapi, który jest przeznaczony do przetwarzania raportów w sposób kolejki. Kroki aplikacja odbywa się w następujący sposób:Jak w kolejce zadań tła w ASP.NET Web API

  • odbierać treści
  • mapie zawartości na obiekt i umieścić go w kolejce
  • Ankietę dla oczekiwaniu pozycji w kolejce
  • elementy procesu w kolejce jednego naraz

Myślałam używać Entity Framework do tworzenia bazy danych oczekujących elementów, takich jak:

public class EFBatchItem 
{ 
    [Key] 
    public string BatchId { get; set; } 
    public DateTime DateCreated { get; set; } 
    public DateTime DateCompleted { get; set; } 
    public string BatchItem { get; set; } 
    public BatchStatus Status { get; set; } 
} 

Moje pytanie - czy istnieje skuteczniejszy sposób korzystania z NServiceBus, BlockingCollection lub ConcurrentQeueue, niż ciągłe odpytywanie bazy danych i wyciąganie oczekujących elementów jeden po drugim? Nie korzystałem wcześniej z kolejek.

Jedną z myśli jest utworzenie kolejki zadań, a na osobnym wątku przetwarzanie wszystkich oczekujących zadań. Nieco podobne do Most efficient way to process a queue with threads, ale chcę mieć pewność, że wybieram najbardziej efektywną trasę.

EDYTOWANIE: Duże pytanie, które mam tutaj, to najlepszy sposób, aby wyświetlić postępy dla użytkownika. Po przesłaniu treści użytkownik zostaje przeniesiony na nową stronę i może wyświetlić status za pomocą identyfikatora partii. Czy MSMQ jest niezbędny, czy NServiceBus, aby powiadomić użytkownika? Wydaje się to być odmianą paradygmatu REQUEST/Acknowledge/Push?

+0

moje rozwiązanie byłoby 'lock' oświadczenie wokół części kodu, w którym piszesz do bazy danych. – efkah

+0

Dzięki za napiwek - nie myślał o tym, i prawdopodobnie spowodowałoby wiele problemów później :) Wszelkie myśli na temat metody kolejkowania? Czy powinienem próbować BlockingCollection, czy po prostu ciągłe odpytywanie bazy danych? Zaktualizował pytanie szybką edycją. – appsecguy

Odpowiedz

23

IMHO, aplikacja ASP.NET Web API nie powinna samodzielnie uruchamiać tych zadań w tle. Powinien być odpowiedzialny tylko za otrzymanie żądania, umieszczenie go w kolejce (tak jak wskazano) i zwrócenie odpowiedzi wskazującej na sukces lub niepowodzenie otrzymanej wiadomości. W tym podejściu można używać różnych systemów przesyłania wiadomości, takich jak RabbitMQ.

Co do powiadomienia, masz kilka opcji. Możesz mieć punkt końcowy, który klient może sprawdzić, czy przetwarzanie zostało zakończone, czy nie. Alternatywnie możesz podać punkt końcowy interfejsu API strumieniowania, który może subskrybować Twój klient. W ten sposób klient nie musi odpytywać serwera; serwer może powiadamiać klientów, którzy są połączeni. ASP.NET Web API ma świetny sposób robienia tego. Poniższy blogu wyjaśnia, jak:

Można również rozważyć SignalR dla tego typu serwera do powiadomienia klienta.

Powodem, dla którego aplikacje ASP.NET Web API są trudne do wykonania w tle, jest odpowiedzialność za utrzymanie przy życiu AppDomain. Jest to uciążliwe, zwłaszcza gdy prowadzisz hosting w IIS. Poniższe blogach wyjaśnia naprawdę dobry, co mam na myśli:

+0

Cóż, zadanie w tle polega zasadniczo na uruchomieniu kilku funkcji ASP.NET w celu automatycznego wygenerowania raportu. Czy mógłbyś wtedy polecić oddzielną aplikację i przekazać jej treść? – appsecguy

+1

@ pendraggon87 co masz na myśli przez "funkcje ASP.NET"? – tugberk

+0

Zasadniczo otrzymuję zawartość, a następnie za pomocą bibliotek Interop do generowania dokumentu programu Word. Zrobiłem aplikację internetową, która pozwoliła użytkownikom generować dokument za pomocą kliknięcia przycisku po wprowadzeniu dużej ilości informacji, ale pracuję teraz tylko nad stworzeniem systemu, w którym mogę wygenerować raport, otrzymując dane JSON. Więc mam cały mój kod napisany, żeby napisać raport. Czy polecasz umieścić ten kod w osobnej aplikacji? – appsecguy

6

Jest to pakiet Nuget i to się nazywa HangFire - https://github.com/HangfireIO/Hangfire. Zadania te utrzymują się nawet poza recyklingiem.

+0

dzięki za ten link, nigdy wcześniej go nie spotkałem, ale mógłbym być tym, czego potrzebuję! – Phil

1

Podoba mi się rozwiązanie @ Todda. Właśnie ze względu na kompletność, ale nie ma innej opcji jeszcze nie wspomniał:

HostingEnvironment.QueueBackgroundWorkItem(cancellationToken => 
{ 
    // Some long-running job 
}); 

Uwaga:

„Kiedy ASP.NET ma do recyklingu, to powiadomi pracy tła (poprzez ustawienie CancellationToken) i następnie czeka aż do 30 sekund na ukończenie pracy.Jeśli praca w tle nie zakończy się w tym czasie, praca zniknie w tajemniczy sposób. "

I unikaj używania metod serwisowych z wstrzykniętym DbContext tutaj, ponieważ to nie zadziała.

Źródła: MariusSchulz i StephenCleary