Hangfire – wysyłka email w tle

W poprzednim wpisie pokazałem, jak w aplikacji ASP.NET MVC wysyłać wiadomości e-mail z wykorzystaniem biblioteki Postal. Wspomniałem również, że wysyłka email w ramach żądania HTTP nie jest dobrym pomysłem, że lepiej skorzystać z jakiegoś mechanizmu kolejek oraz ponawiania operacji. Jednym z dostępnych narzędzi jest biblioteka Hangfire, która w prosty sposób może wysłać e-mail w tle, a do tego ponowić operację w momencie wystąpienia błędu.

Hangfire

Ostatnio do kolejkowania zadań oraz wykonywania ich w tle wykorzystuję bibliotekę Hangfire (https://www.hangfire.io/). Lubię ją z kilku powodów:

  • Jest darmowa, więc nie muszę płacić – jest również wersja płatna z kilkoma ciekawymi funkcjonalnościami, ale na ogół ich nie potrzebuję.
  • Bardzo łatwa integracja z aplikacją ASP.NET MVC – w praktyce wystarczy dodać kilka linijek w Startup.cs, aby korzystać z zadań wykonywanych w tle.
  • Fajny dashboard z informacjami o wykonywanych zadaniach.
  • Możliwość wykonywania zadań na różnych komputerach, więc relatywnie łatwo można skalować wykonywanie zadań na kilka maszyn.
  • Jest elastyczna w wykorzystywaniu poszczególnych elementów biblioteki, zadania mogą być wykonywane w zupełnie innej aplikacji niż ta, w której są dodawane, podobnie z dashboardem.
  • Wersja płatna jest relatywnie tania – 500$ za organizację (nie programistę, jak to bywa na ogół) za rok.

Hangfire – instalacja oraz konfiguracja

Standardowo w pierwszej kolejności instalujemy pakiet Hangfire (https://www.nuget.org/packages/HangFire). Domyślnie Hangfire korzysta z bazy danych MS Sql Server do przechowywania informacji o zadaniach. W wersji płatnej możemy skorzystać z Redisa. Jak podają twórcy biblioteki, implementacja z wykorzystaniem Redisa jest około 4 razy szybsza niż wykorzystywanie bazy danych.

W przypadku MS Sql Servera możemy użyć tej samej bazy, w której normalnie przechowujemy dane, lub zdecydować się na dedykowaną bazę dla biblioteki. W przykładzie dodałem connection stringa do web.config:

Mając skonfigurowane źródło przechowywania danych, możemy skonfigurować już samą bibliotekę. Wszystko robi się w pliku Startup.cs:

Konfiguracja składa się z wywołania trzech metod:

  • UseSqlServerStorage – informuje, że korzystamy z bazy MS Sql Server do przechowywania informacji oraz przekazuje nazwę connection stringa, którego ma użyć biblioteka.
  • UseHangfireDashboard – informuje, że w aplikacji ma być dostępny dashboard z informacjami o zadaniach.
  • UseHangfireServer – informuje, że w ramach aplikacji mają działać workery, które będą wykonywać zadania.

Jak wspomniałem wcześniej, poszczególne elementy biblioteki możemy zaimplementować w różnych aplikacjach. Możemy na przykład mieć jedną aplikację z dashboardami z wszystkich aplikacji, w której wykorzystujemy Hangfire. Aplikacja może działać tylko w sieci lokalnej firmy i nie ma do niej dostępu z Internetu.

Darmowy kurs Visual Studio

Pracując z setkami programistów, zauważyłem, że większość osób nie pracuje efektywnie w Visual Studio. W skrajnych przypadkach korzystali z kopiowania z wykorzystaniem menu Edit. Wiem, że to dziwne, ale naprawdę niektórzy tak pracują. Dlatego postanowiłem stworzyć kurs Visual Studio – aby pomóc koleżankom i kolegom w efektywniejszej pracy.

Przygotowałem 20 lekcji e-mail, w których pokażę Ci, w jaki sposób pracować efektywniej i szybciej w Visual Studio. Poznasz dodatki, bez których nie wyobrażam sobie pracy w tym IDE.

Po więcej informacji zapraszam na dedykowaną stronę kursu: Darmowy Kurs Visual Studio.

Quiz C#

Ostatnio przygotowałem również quiz C#, w którym możesz sprawdzić swoją wiedzę. Podejmiesz wyzwanie?

Dodanie zadania do wykonania

Po skonfigurowaniu Hangfire samo dodanie zadania do wykonania jest bardzo proste. Wystarczy zamienić wywołanie właściwej metody (np. SendRegisterEmail z klasy UserMailer) na wywołanie statycznej metody Enqueue z klasy BackgroundJob (są też inne sposoby, ale o tym w późniejszych wpisach), gdzie w parametrze przekazujemy w formie lambdy wcześniejsze wywołanie. Poniżej znajduje się metoda z logiki biznesowej pokazująca dodanie zadania polegającego na wysłaniu wiadomości e-mail. W komentarzu znajduje się również wcześniejsza wersja, dla porównania.

Wykonanie zadania oraz dashboard

Mając już zmieniony kod, możemy spróbować dodać nowego użytkownika, aby system wysłał wiadomość e-mail z wykorzystaniem Hangfire. Po dodaniu zadania pojawi się ono na liście w dashboardzie. Domyślnie dashboard dostępny jest pod adresem [adres aplikacji]/hangfire. W dashboardzie możemy zobaczyć listę zadań z podziałem na statusy (do wykonania, wykonywane, zakończone itp.) czy też możemy zobaczyć szczegóły zadania (zserializowane dane zadania, informacje o ilości wykonywań czy błędy, gdy nie udało się wykonać zadania).

Hangfire lista zadań

Hangfire szczegóły zadania

Hangfire, Postal oraz kontener DI (Autofac)

Na koniec jeszcze jedna istotna informacja na temat integracji Hangfire, Postal oraz kontenera Dependency Injection, w moim przypadku – Autofac. Niestety, kiedy w aplikacji chcecie połączyć te trzy biblioteki (podobnie może być z innymi kontenerami, które wspierają cykl życia obiektu per żądanie HTTP), podczas wykonywania zadania z wysyłką wiadomości otrzymacie błąd, że wymagany jest kontekst HTTP do utworzenia jakiegoś obiektu. Widać to na poniższym zrzucie zadania (co fajne, po poprawieniu błędu zadanie zostało poprawnie wykonane i wiadomość została wysłana w jednej z kolejnych prób, a to pokazuje, że Hangfire działa :)):

Hangfire błąd z zadaniu

Takie działanie aplikacji spowodowane jest tym, że klasa ViewEngineCollection, którą wykorzystujemy w metodzie Send z klasy BaseMailer, w swoim kodzie korzysta z ustawionego w ASP.NET MVC resolvera (czyli w moim przypadku skonfigurowanego kontenera Autofac). Próbuję za jego pomocą wyciągnąć obiekty wewnętrzne z silnika, a one mają ustawiony cykl życia per żądanie. Co ciekawe, tamte obiekty nie są potrzebne do poprawnego wygenerowania treści wiadomości. Jednym z rozwiązań jest stworzenie własnej klasy dziedziczącej po ViewEngineCollection i, w konstruktorze za pomocą refleksji, zmiana wykorzystywanego resolvera, aby klasa nie korzystała z kontenera. Poniżej znajduje się zmieniona klasa BaseMailer, która właśnie wykorzystuje zmienioną klasę ViewEngineCollection. W przypadku gdy nie korzystamy z kontenera, zmiana wcześniejszego kodu nie jest potrzebna.

Podsumowanie

Dodanie wykonywania zadań z wykorzystaniem kolejek nie musi być bardzo trudne. Dzięki bibliotece Hangfire może być to wręcz łatwe i przyjemne. Jak widać, daje to dużą niezawodność w działaniu aplikacji, poprzez możliwość ponawiania wykonywania zadań, które się nie udały. Dodatkowo przejrzysty dashboard daje dużo informacji o tym, co dzieje się z zadaniami w aplikacji.

Testowy projekt tradycyjnie znajdziesz na moim githubie. Zapraszam do pobrania i przetestowania w praktyce biblioteki Hangfire.

A Tobie jak podoba się Hangfire? Znałeś wcześniej tę bibliotekę? A może używasz czegoś fajniejszego? Daj znać w komentarzu.

 

5 thoughts on “Hangfire – wysyłka email w tle

Dodaj komentarz

Twój adres email nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *