Tworzenie aplikacji biznesowych opartych na komunikatach za pomocą sieci NServiceBus i usługi Azure Service Bus
NServiceBus to komercyjna platforma obsługi komunikatów dostarczana przez określone oprogramowanie. Jest ona oparta na usłudze Azure Service Bus i pomaga deweloperom skupić się na logice biznesowej przez abstrakcję problemów z infrastrukturą. W tym przewodniku utworzymy rozwiązanie, które wymienia komunikaty między dwiema usługami. Pokażemy również, jak automatycznie ponowić próbę niepowodzenia komunikatów i przejrzeć opcje hostowania tych usług na platformie Azure.
Uwaga
Kod tego samouczka jest dostępny w witrynie sieci Web Konkretnej witryny dokumentacji oprogramowania.
Wymagania wstępne
W przykładzie założono, że utworzono przestrzeń nazw usługi Azure Service Bus.
Ważne
NServiceBus wymaga co najmniej warstwy Standardowa. Warstwa Podstawowa nie będzie działać.
Pobieranie i przygotowywanie rozwiązania
Pobierz kod z witryny sieci Web Docs określonego oprogramowania. Rozwiązanie
SendReceiveWithNservicebus.sln
składa się z trzech projektów:- Nadawca: aplikacja konsolowa, która wysyła komunikaty
- Odbiornik: aplikacja konsolowa, która odbiera komunikaty od nadawcy i odpowiada z powrotem
- Udostępnione: biblioteka klas zawierająca kontrakty komunikatów współużytkowane przez nadawcę i odbiorcę
Na poniższym diagramie wygenerowanym przez usługę ServiceInsight, narzędziu do wizualizacji i debugowania z określonego oprogramowania przedstawiono przepływ komunikatów:
Otwórz plik
SendReceiveWithNservicebus.sln
w ulubionym edytorze kodu (na przykład Visual Studio 2022).Otwórz
appsettings.json
zarówno w projektach Odbiornik, jak i Nadawca, a następnie ustawAzureServiceBusConnectionString
parametry połączenia dla przestrzeni nazw usługi Azure Service Bus.- Można to znaleźć w witrynie Azure Portal w obszarze Ustawienia przestrzeni nazw>>usługi Service Bus Zasady>dostępu współdzielonego RootManageSharedAccessKey>podstawowe parametry połączenia.
- Ma
AzureServiceBusTransport
również konstruktor, który akceptuje przestrzeń nazw i poświadczenia tokenu, które w środowisku produkcyjnym będzie bezpieczniejsze, jednak na potrzeby tego samouczka zostanie użyty klucz dostępu współdzielonego parametry połączenia.
Definiowanie kontraktów komunikatów udostępnionych
Biblioteka klas udostępnionych służy do definiowania kontraktów używanych do wysyłania naszych komunikatów. Zawiera on odwołanie do NServiceBus
pakietu NuGet, który zawiera interfejsy, których można użyć do identyfikowania naszych komunikatów. Interfejsy nie są wymagane, ale dają nam dodatkową walidację z NServiceBus i umożliwiają samodzielne dokumentowanie kodu.
Najpierw przejrzymy klasę Ping.cs
public class Ping : NServiceBus.ICommand
{
public int Round { get; set; }
}
Klasa Ping
definiuje komunikat, który nadawca wysyła do odbiorcy. Jest to prosta klasa języka C#, która implementuje NServiceBus.ICommand
interfejs z pakietu NServiceBus. Ten komunikat jest sygnałem dla czytnika i NServiceBus, że jest to polecenie, chociaż istnieją inne sposoby identyfikowania komunikatów bez używania interfejsów.
Druga klasa komunikatów w projektach udostępnionych to Pong.cs
:
public class Pong : NServiceBus.IMessage
{
public string Acknowledgement { get; set; }
}
Pong
jest również prostym obiektem języka C#, choć ten implementuje NServiceBus.IMessage
element . Interfejs IMessage
reprezentuje ogólny komunikat, który nie jest ani poleceniem, ani zdarzeniem, i jest często używany do odpowiedzi. W naszym przykładzie jest to odpowiedź, którą odbiorca wysyła z powrotem do nadawcy, aby wskazać, że wiadomość została odebrana.
Wartości Ping
i Pong
to dwa typy komunikatów, których będziesz używać. Następnym krokiem jest skonfigurowanie nadawcy do używania usługi Azure Service Bus i wysłania komunikatu Ping
.
Konfigurowanie nadawcy
Nadawca to punkt końcowy, który wysyła wiadomość Ping
. W tym miejscu skonfigurujesz nadawcę do używania usługi Azure Service Bus jako mechanizmu transportu, a następnie skonstruujesz Ping
wystąpienie i wyślesz je.
W metodzie Main
Program.cs
programu należy skonfigurować punkt końcowy nadawcy:
var host = Host.CreateDefaultBuilder(args)
// Configure a host for the endpoint
.ConfigureLogging((context, logging) =>
{
logging.AddConfiguration(context.Configuration.GetSection("Logging"));
logging.AddConsole();
})
.UseConsoleLifetime()
.UseNServiceBus(context =>
{
// Configure the NServiceBus endpoint
var endpointConfiguration = new EndpointConfiguration("Sender");
var connectionString = context.Configuration.GetConnectionString("AzureServiceBusConnectionString");
// If token credentials are to be used, the overload constructor for AzureServiceBusTransport would be used here
var routing = endpointConfiguration.UseTransport(new AzureServiceBusTransport(connectionString));
endpointConfiguration.UseSerialization<SystemJsonSerializer>();
endpointConfiguration.AuditProcessedMessagesTo("audit");
routing.RouteToEndpoint(typeof(Ping), "Receiver");
endpointConfiguration.EnableInstallers();
return endpointConfiguration;
})
.ConfigureServices(services => services.AddHostedService<SenderWorker>())
.Build();
await host.RunAsync();
Istnieje wiele do rozpakowania tutaj, więc zapoznamy się z nim krok po kroku.
Konfigurowanie hosta dla punktu końcowego
Hosting i rejestrowanie są konfigurowane przy użyciu standardowych opcji hosta ogólnego firmy Microsoft. Na razie punkt końcowy jest skonfigurowany do uruchamiania jako aplikacja konsolowa, ale można go zmodyfikować w celu uruchamiania w usłudze Azure Functions z minimalnymi zmianami, które omówimy w dalszej części tego artykułu.
Konfigurowanie punktu końcowego NServiceBus
Następnie należy poinformować hosta o użyciu narzędzia NServiceBus z .UseNServiceBus(…)
metodą rozszerzenia. Metoda przyjmuje funkcję wywołania zwrotnego, która zwraca punkt końcowy, który zostanie uruchomiony po uruchomieniu hosta.
W konfiguracji punktu końcowego określisz AzureServiceBus
dla naszego transportu, podając parametry połączenia z appsettings.json
. Następnie skonfigurujesz routing, aby komunikaty typu Ping
zostały wysłane do punktu końcowego o nazwie "Odbiornik". Dzięki niej NServiceBus może zautomatyzować proces wysyłania komunikatu do miejsca docelowego bez wymagania adresu odbiorcy.
Wywołanie metody , aby EnableInstallers
skonfigurować naszą topologię w przestrzeni nazw usługi Azure Service Bus po uruchomieniu punktu końcowego, tworząc wymagane kolejki w razie potrzeby. W środowiskach produkcyjnych skrypty operacyjne to kolejna opcja tworzenia topologii.
Konfigurowanie usługi w tle w celu wysyłania komunikatów
Ostatnim elementem nadawcy jest SenderWorker
usługa w tle skonfigurowana do wysyłania komunikatu Ping
co sekundę.
public class SenderWorker : BackgroundService
{
private readonly IMessageSession messageSession;
private readonly ILogger<SenderWorker> logger;
public SenderWorker(IMessageSession messageSession, ILogger<SenderWorker> logger)
{
this.messageSession = messageSession;
this.logger = logger;
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
try
{
var round = 0;
while (!stoppingToken.IsCancellationRequested)
{
await messageSession.Send(new Ping { Round = round++ });;
logger.LogInformation($"Message #{round}");
await Task.Delay(1_000, stoppingToken);
}
}
catch (OperationCanceledException)
{
// graceful shutdown
}
}
}
Używany IMessageSession
element jest ExecuteAsync
wstrzykiwany do SenderWorker
elementu i umożliwia wysyłanie komunikatów przy użyciu protokołu NServiceBus poza programem obsługi komunikatów. Routing skonfigurowany w programie Sender
określa miejsce docelowe komunikatów Ping
. Utrzymuje topologię systemu (które komunikaty są kierowane do których adresów) są oddzielone od kodu biznesowego.
Aplikacja Nadawca zawiera również element PongHandler
. Wrócisz do niego po omówieniu odbiornika, który zrobimy dalej.
Konfigurowanie odbiornika
Odbiornik to punkt końcowy, który nasłuchuje komunikatu Ping
, rejestruje po odebraniu komunikatu i odpowiada z powrotem do nadawcy. W tej sekcji szybko sprawdzimy konfigurację punktu końcowego, która jest podobna do nadawcy, a następnie zwrócimy uwagę na procedurę obsługi komunikatów.
Podobnie jak nadawca, skonfiguruj odbiornik jako aplikację konsolową przy użyciu hosta ogólnego firmy Microsoft. Używa tej samej konfiguracji rejestrowania i punktu końcowego (z usługą Azure Service Bus jako transportem komunikatów), ale z inną nazwą, aby odróżnić ją od nadawcy:
var endpointConfiguration = new EndpointConfiguration("Receiver");
Ponieważ ten punkt końcowy odpowiada tylko na jego inicjatora i nie uruchamia nowych konwersacji, nie jest wymagana żadna konfiguracja routingu. Nie potrzebuje również procesu roboczego w tle, takiego jak nadawca, ponieważ odpowiada tylko wtedy, gdy otrzymuje komunikat.
Procedura obsługi komunikatów ping
Projekt Receiver zawiera procedurę obsługi komunikatów o nazwie PingHandler
:
public class PingHandler : NServiceBus.IHandleMessages<Ping>
{
private readonly ILogger<PingHandler> logger;
public PingHandler(ILogger<PingHandler> logger)
{
this.logger = logger;
}
public async Task Handle(Ping message, IMessageHandlerContext context)
{
logger.LogInformation($"Processing Ping message #{message.Round}");
// throw new Exception("BOOM");
var reply = new Pong { Acknowledgement = $"Ping #{message.Round} processed at {DateTimeOffset.UtcNow:s}" };
await context.Reply(reply);
}
}
Zignorujmy na razie skomentowany kod; Wrócimy do niego później, gdy będziemy mówić o odzyskiwaniu po awarii.
Klasa implementuje IHandleMessages<Ping>
metodę , która definiuje jedną metodę: Handle
. Ten interfejs informuje NServiceBus, że gdy punkt końcowy odbiera komunikat typu Ping
, powinien zostać przetworzony przez metodę Handle
w tej procedurze obsługi. Metoda Handle
przyjmuje sam komunikat jako parametr i IMessageHandlerContext
, który umożliwia dalsze operacje obsługi komunikatów, takie jak odpowiadanie, wysyłanie poleceń lub publikowanie zdarzeń.
Nasza PingHandler
funkcja jest prosta: po odebraniu Ping
komunikatu należy zarejestrować szczegóły wiadomości i odpowiedzieć z powrotem do nadawcy przy użyciu nowej Pong
wiadomości, która jest następnie obsługiwana w elemecie Nadawca PongHandler
.
Uwaga
W konfiguracji nadawcy określono, że Ping
komunikaty powinny być kierowane do odbiorcy. NServiceBus dodaje metadane do komunikatów wskazujących między innymi źródło komunikatu. Dlatego nie trzeba określać żadnych danych routingu Pong
dla wiadomości odpowiedzi— jest ona automatycznie kierowana z powrotem do źródła: nadawcy.
Po poprawnym skonfigurowaniu nadawcy i odbiorcy można teraz uruchomić rozwiązanie.
Uruchamianie rozwiązania
Aby uruchomić rozwiązanie, należy uruchomić zarówno nadawcę, jak i odbiorcę. Jeśli używasz programu Visual Studio Code, uruchom konfigurację "Debuguj wszystko". Jeśli używasz programu Visual Studio, skonfiguruj rozwiązanie tak, aby uruchamiało projekty nadawcy i odbiorcy:
- Kliknij rozwiązanie prawym przyciskiem myszy w Eksplorator rozwiązań
- Wybierz pozycję "Ustaw projekty startowe..."
- Wybieranie wielu projektów startowych
- W przypadku nadawcy i odbiorcy wybierz pozycję "Uruchom" na liście rozwijanej
Uruchom rozwiązanie. Zostaną wyświetlone dwie aplikacje konsolowe: jedna dla nadawcy i jedna dla odbiornika.
W nadawcy zwróć uwagę, że Ping
komunikat jest wysyłany co sekundę dzięki SenderWorker
zadaniu w tle. Odbiorca wyświetla szczegóły każdego Ping
odbieranego komunikatu, a nadawca rejestruje szczegóły każdego Pong
odbieranego komunikatu w odpowiedzi.
Teraz, gdy wszystko działa, przerwijmy go.
Odporność w działaniu
Błędy to fakt życia w systemach oprogramowania. Nieuniknione jest, że kod zakończy się niepowodzeniem i może to zrobić z różnych powodów, takich jak awarie sieci, blokady bazy danych, zmiany w interfejsie API innej firmy i zwykłe stare błędy kodowania.
NServiceBus ma niezawodne funkcje odzyskiwania do obsługi błędów. Gdy program obsługi komunikatów zakończy się niepowodzeniem, komunikaty są automatycznie ponawiane na podstawie wstępnie zdefiniowanych zasad. Istnieją dwa typy zasad ponawiania prób: natychmiastowe ponawianie prób i opóźnione próby. Najlepszym sposobem opisania sposobu ich działania jest sprawdzenie ich w działaniu. Dodajmy zasady ponawiania do punktu końcowego odbiorcy:
- Otwórz
Program.cs
w projekcie Nadawca .EnableInstallers
Po wierszu dodaj następujący kod:
endpointConfiguration.SendFailedMessagesTo("error");
var recoverability = endpointConfiguration.Recoverability();
recoverability.Immediate(
immediate =>
{
immediate.NumberOfRetries(3);
});
recoverability.Delayed(
delayed =>
{
delayed.NumberOfRetries(2);
delayed.TimeIncrease(TimeSpan.FromSeconds(5));
});
Zanim omówimy działanie tych zasad, zobaczmy ją w działaniu. Przed przetestowaniem zasad możliwości odzyskiwania należy zasymulować błąd. PingHandler
Otwórz kod w projekcie Receiver i usuń komentarz w tym wierszu:
throw new Exception("BOOM");
Teraz, gdy odbiornik obsługuje komunikat, zakończy się niepowodzeniem Ping
. Uruchom rozwiązanie ponownie i zobaczmy, co się dzieje w odbiorniku.
Dzięki naszym mniej niezawodnym PingHandler
komunikatom wszystkie komunikaty kończą się niepowodzeniem. Możesz zobaczyć, że zasady ponawiania są uruchamiane dla tych komunikatów. Przy pierwszym niepomyślnym zakończeniu komunikatu następuje natychmiastowe ponowienia próby do trzech razy:
Oczywiście będzie ona nadal się nie powieść, więc gdy zostaną użyte trzy natychmiastowe ponawianie prób, opóźnione ponowne próby zostaną uruchomione, a komunikat zostanie opóźniony przez 5 sekund:
Po upływie tych 5 sekund komunikat zostanie ponowiony ponownie trzy razy (oznacza to kolejną iterację natychmiastowych zasad ponawiania). Zakończy się to również niepowodzeniem, a usługa NServiceBus ponownie opóźni komunikat, tym razem przez 10 sekund, przed ponowną próbą.
Jeśli PingHandler
nadal nie powiedzie się po uruchomieniu przez pełne zasady ponawiania prób, komunikat zostanie umieszczony w scentralizowanej kolejce błędów o nazwie error
, zgodnie z definicją przez wywołanie metody .SendFailedMessagesTo
Koncepcja scentralizowanej kolejki błędów różni się od mechanizmu utraconych komunikatów w usłudze Azure Service Bus, który ma kolejkę utraconych komunikatów dla każdej kolejki przetwarzania. W przypadku magistrali NServiceBus kolejki utraconych komunikatów w usłudze Azure Service Bus działają jako prawdziwe kolejki komunikatów trucizny, podczas gdy komunikaty, które kończą się w scentralizowanej kolejce błędów, można ponownie przetworzyć w późniejszym czasie, w razie potrzeby.
Zasady ponawiania prób pomagają rozwiązać kilka typów błędów , które często są przejściowe lub częściowo przejściowe w naturze. Oznacza to, że błędy, które są tymczasowe i często odchodzą, jeśli komunikat jest po prostu ponownie przetworzony po krótkim opóźnieniu. Przykłady obejmują błędy sieci, blokady bazy danych i awarie interfejsu API innych firm.
Gdy komunikat znajduje się w kolejce błędów, możesz sprawdzić szczegóły komunikatu w wybranym narzędziu, a następnie zdecydować, co z nim zrobić. Na przykład przy użyciu usługi ServicePulse narzędzie do monitorowania według określonego oprogramowania możemy wyświetlić szczegóły komunikatu i przyczynę błędu:
Po zbadaniu szczegółów możesz wysłać komunikat z powrotem do oryginalnej kolejki na potrzeby przetwarzania. Przed wykonaniem tej czynności możesz również edytować komunikat. Jeśli w kolejce błędów znajduje się wiele komunikatów, które zakończyły się niepowodzeniem z tego samego powodu, wszystkie mogą być wysyłane z powrotem do oryginalnych miejsc docelowych jako partia.
Następnie nadszedł czas, aby dowiedzieć się, gdzie wdrożyć nasze rozwiązanie na platformie Azure.
Gdzie hostować usługi na platformie Azure
W tym przykładzie punkty końcowe nadawcy i odbiorcy są skonfigurowane do uruchamiania jako aplikacje konsolowe. Mogą one być również hostowane w różnych usługach platformy Azure, takich jak Azure Functions, aplikacja systemu Azure Services, Azure Container Instances, Azure Kubernetes Services i Maszyny wirtualne platformy Azure. Na przykład poniżej przedstawiono sposób konfigurowania punktu końcowego nadawcy do uruchamiania jako funkcji platformy Azure:
[assembly: NServiceBusTriggerFunction("Sender")]
public class Program
{
public static async Task Main()
{
var host = new HostBuilder()
.ConfigureFunctionsWorkerDefaults()
.UseNServiceBus(configuration =>
{
configuration.Routing().RouteToEndpoint(typeof(Ping), "Receiver");
})
.Build();
await host.RunAsync();
}
}
Aby uzyskać więcej informacji na temat korzystania z usługi NServiceBus z usługą Functions, zobacz Azure Functions with Azure Service Bus (Usługa Azure Functions z usługą Azure Service Bus ) w dokumentacji NServiceBus.
Następne kroki
Aby uzyskać więcej informacji na temat korzystania z sieci NServiceBus z usługami platformy Azure, zobacz następujące artykuły: