Üzenetvezérelt üzleti alkalmazások létrehozása NServiceBus és Azure Service Bus használatával

Az NServiceBus egy adott szoftver által biztosított kereskedelmi üzenetkezelési keretrendszer. A Azure Service Bus alapul, és az infrastruktúra problémáinak absztrakciója révén segít a fejlesztőknek az üzleti logikára összpontosítani. Ebben az útmutatóban egy olyan megoldást hozunk létre, amely üzeneteket cserél két szolgáltatás között. Azt is bemutatjuk, hogyan lehet automatikusan újrapróbálkozhat a sikertelen üzenetekkel, és áttekintjük a szolgáltatások Azure-ban való üzemeltetésének lehetőségeit.

Megjegyzés

Az oktatóanyag kódja az Adott szoftver docs webhelyén érhető el.

Előfeltételek

A minta feltételezi, hogy létrehozott egy Azure Service Bus névteret.

Fontos

Az NServiceBus használatához legalább a Standard szint szükséges. Az Alapszintű szint nem fog működni.

A megoldás letöltése és előkészítése

  1. Töltse le a kódot az Adott szoftver docs webhelyről. A megoldás SendReceiveWithNservicebus.sln három projektből áll:

    • Feladó: üzeneteket küldő konzolalkalmazás
    • Fogadó: egy konzolalkalmazás, amely üzeneteket fogad a feladótól és válaszol vissza
    • Megosztott: a feladó és a fogadó között megosztott üzenetszerződéseket tartalmazó osztálytár

    A ServiceInsight által létrehozott alábbi diagram, amely egy adott szoftver vizualizációs és hibakeresési eszköze, az üzenetfolyamot mutatja be:

    A szekvenciadiagramot ábrázoló kép

  2. Nyissa meg SendReceiveWithNservicebus.sln a kedvenc kódszerkesztőjében (például Visual Studio 2019).

  3. Nyissa meg appsettings.json a Fogadó és a Feladó projektben is, és állítsa a AzureServiceBusConnectionString Azure Service Bus névtér kapcsolati sztring.

A megosztott üzenetszerződések meghatározása

A Megosztott osztálytárban határozhatja meg az üzenetek küldéséhez használt szerződéseket. Tartalmaz egy hivatkozást a NServiceBus NuGet-csomagra, amely olyan felületeket tartalmaz, amelyekkel azonosíthatja az üzeneteinket. Az interfészek nem szükségesek, de további ellenőrzést biztosítanak az NServiceBustól, és lehetővé teszik a kód ön dokumentálását.

Először áttekintjük az osztályt Ping.cs

public class Ping : NServiceBus.ICommand
{
    public int Round { get; set; }
}

A Ping osztály meghatároz egy üzenetet, amelyet a feladó küld a fogadónak. Ez egy egyszerű C#-osztály, amely implementálja NServiceBus.ICommandaz NServiceBus-csomag felületét. Ez az üzenet jelzi az olvasónak és az NServiceBusnak, hogy ez egy parancs, bár más módokon is azonosíthatja az üzeneteket interfészek használata nélkül.

A megosztott projektek másik üzenetosztálya a következő Pong.cs:

public class Pong : NServiceBus.IMessage
{
    public string Acknowledgement { get; set; }
}

Pong is egy egyszerű C# objektum, bár ez implementálja NServiceBus.IMessage. A IMessage felület egy általános üzenetet jelöl, amely nem parancs, sem esemény, és gyakran használják válaszokhoz. A mintában ez egy válasz, amelyet a fogadó visszaküld a feladónak, jelezve, hogy üzenet érkezett.

A Ping és Pong a két üzenettípust fogja használni. A következő lépésben konfigurálja a feladót arra, hogy Azure Service Bus használjon, és küldjön üzenetetPing.

A feladó beállítása

A Küldő egy végpont, amely elküldi Ping az üzenetet. Itt konfigurálja a Feladót úgy, hogy a Azure Service Bus használja átviteli mechanizmusként, majd hozzon létre egy példánytPing, és küldje el.

A metódusában Program.cskonfigurálja Main a Sender végpontot:

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 transport = endpointConfiguration.UseTransport<AzureServiceBusTransport>();
        var connectionString = context.Configuration.GetConnectionString("AzureServiceBusConnectionString");
        transport.ConnectionString(connectionString);

        transport.Routing().RouteToEndpoint(typeof(Ping), "Receiver");

        endpointConfiguration.EnableInstallers();
        endpointConfiguration.AuditProcessedMessagesTo("audit");

        return endpointConfiguration;
    })
    .ConfigureServices(services => services.AddHostedService<SenderWorker>())
    .Build();

await host.RunAsync();

Itt sok mindent ki kell csomagolni, ezért lépésről lépésre áttekintjük.

Gazdagép konfigurálása a végponthoz

Az üzemeltetés és a naplózás a Microsoft Generic Host standard beállításaival van konfigurálva. A végpont jelenleg úgy van konfigurálva, hogy konzolalkalmazásként fusson, de módosítható úgy, hogy minimális módosításokkal fusson Azure Functions. Erről a cikk későbbi részében lesz szó.

Az NServiceBus-végpont konfigurálása

Ezután meg kell mondania a gazdagépnek, hogy az NServiceBust használja a .UseNServiceBus(…) bővítménymetódussal. A metódus egy visszahívási függvényt fogad, amely egy végpontot ad vissza, amely a gazdagép futtatásakor indul el.

A végpontkonfigurációban megadhatja AzureServiceBus az átvitelt, és kapcsolati sztring a-bólappsettings.json. Ezután beállítja az útválasztást, hogy a típusú Ping üzenetek egy "Receiver" nevű végpontra legyenek elküldve. Ez lehetővé teszi, hogy az NServiceBus automatizálja az üzenet célhelyre történő elküldésének folyamatát a címzett címének megkövetelése nélkül.

A hívás EnableInstallers a végpont indításakor beállítja a topológiát a Azure Service Bus névtérben, és szükség esetén létrehozza a szükséges üzenetsorokat. Éles környezetekben az operatív szkriptelés egy másik lehetőség a topológia létrehozására.

Háttérszolgáltatás beállítása üzenetek küldéséhez

A feladó SenderWorkerutolsó része egy háttérszolgáltatás, amely úgy van konfigurálva, hogy másodpercenként küldjön üzenetet Ping .

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++ })
                    .ConfigureAwait(false);

                logger.LogInformation($"Message #{round}");

                await Task.Delay(1_000, stoppingToken)
                    .ConfigureAwait(false);
            }
        }
        catch (OperationCanceledException)
        {
            // graceful shutdown
        }
    }
}

A IMessageSession beszúrt fájlba SenderWorker a rendszer beszúrja a fájltExecuteAsync, és lehetővé teszi, hogy az NServiceBus használatával üzeneteket küldjünk egy üzenetkezelőn kívül. Az itt konfigurált Sender útválasztás határozza meg az üzenetek célját Ping . A rendszer topológiáját (mely üzeneteket melyik címekre irányítja) az üzleti kódtól külön kezeli.

A Sender alkalmazás egy PongHandlerelemet is tartalmaz. Ha már megbeszéltük a Fogadót, visszatérünk hozzá, amit a következő lépésként fogunk megtenni.

A fogadó beállítása

A fogadó egy végpont, amely figyeli az Ping üzenetet, naplózza az üzenet fogadását, és válaszol a feladónak. Ebben a szakaszban gyorsan áttekintjük a végpont konfigurációját, amely hasonló a Feladóhoz, majd a figyelmünket az üzenetkezelőre irányítjuk.

A feladóhoz hasonlóan állítsa be a fogadót konzolalkalmazásként a Microsoft Generic Host használatával. Ugyanazt a naplózási és végpontkonfigurációt használja (Azure Service Bus, mint az üzenetátvitel), de más néven, hogy megkülönböztesse a feladótól:

var endpointConfiguration = new EndpointConfiguration("Receiver");

Mivel ez a végpont csak a kezdeményezőjének válaszol, és nem indít új beszélgetéseket, nincs szükség útválasztási konfigurációra. A feladóhoz hasonlóan nincs szüksége háttér-feldolgozóra, mivel csak akkor válaszol, ha üzenetet kap.

A Ping üzenetkezelő

A Receiver projekt egy nevű üzenetkezelőtPingHandlertartalmaz:

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);
    }
}

Most hagyja figyelmen kívül a megjegyzésben szereplő kódot; Később visszatérünk hozzá, amikor a meghibásodás utáni helyreállításról beszélünk.

A osztály implementálja a metódust IHandleMessages<Ping>, amely egy metódust határoz meg: Handle. Ez az interfész tájékoztatja az NServiceBust, hogy amikor a végpont egy típusú Pingüzenetet kap, azt a Handle kezelő metódusának kell feldolgoznia. A Handle metódus magát az üzenetet veszi paraméterként, és egy paramétert IMessageHandlerContext, amely további üzenetkezelési műveleteket tesz lehetővé, például a válaszadást, a parancsok küldését vagy az események közzétételét.

A mi üzenetünk PingHandler egyszerű: üzenet érkezésekor Ping naplózza az üzenet részleteit, és válaszoljon vissza a feladónak egy új Pong üzenettel.

Megjegyzés

A Feladó konfigurációjában azt adta meg, hogy Ping az üzeneteket a fogadóhoz kell irányítani. Az NServiceBus metaadatokat ad hozzá az üzenetekhez, amelyek többek között az üzenet eredetét jelzik. Ezért nem kell útválasztási adatokat megadnia a Pong válaszüzenethez; az automatikusan vissza lesz irányítva a feladóhoz: a feladóhoz.

A küldő és a fogadó megfelelően konfigurálva van, így futtathatja a megoldást.

A megoldás futtatása

A megoldás elindításához a feladót és a fogadót is futtatnia kell. Ha Visual Studio Code-ot használ, indítsa el az "Összes hibakeresése" konfigurációt. Ha Visual Studiót használ, konfigurálja úgy a megoldást, hogy a Küldő és a Fogadó projektet is elindítsa:

  1. Kattintson a jobb gombbal a megoldásra a Megoldáskezelő
  2. Válassza az "Indítási projektek beállítása..." lehetőséget.
  3. Több indítási projekt kiválasztása
  4. A Feladó és a Fogadó esetében is válassza a "Start" lehetőséget a legördülő listában

Indítsa el a megoldást. Két konzolalkalmazás jelenik meg, egy a Feladó és egy a Fogadó számára.

A Küldőben figyelje meg, hogy a háttérfeladatnak köszönhetően SenderWorker minden másodpercben elküld egy Ping üzenetet. A Fogadó megjeleníti a kapott üzenetek részleteit Ping , a Feladó pedig naplózza a válaszban kapott üzenetek Pong részleteit.

Most, hogy minden működik, törjük meg.

Rugalmasság működés közben

A hibák a szoftverrendszerek életének tényei. Elkerülhetetlen, hogy a kód meghiúsuljon, és ennek számos oka lehet, például hálózati hibák, adatbázis-zárolások, külső API-k változásai és egyszerű régi kódolási hibák.

Az NServiceBus robusztus helyreállíthatósági funkciókkal rendelkezik a hibák kezeléséhez. Ha egy üzenetkezelő meghibásodik, az üzenetek automatikusan újrapróbálkoznak egy előre meghatározott szabályzat alapján. Az újrapróbálkozásoknak két típusa van: azonnali újrapróbálkozások és késleltetett újrapróbálkozások. A legjobb módja annak, hogy leírja, hogyan működnek, ha működés közben látja őket. Adjunk hozzá egy újrapróbálkozési szabályzatot a Fogadó végponthoz:

  1. Megnyitás Program.cs a Sender projektben
  2. .EnableInstallers A sor után adja hozzá a következő kódot:
endpointConfiguration.SendFailedMessagesTo("error");
var recoverability = endpointConfiguration.Recoverability();
recoverability.Immediate(
    immediate =>
    {
        immediate.NumberOfRetries(3);
    });
recoverability.Delayed(
    delayed =>
    {
        delayed.NumberOfRetries(2);
        delayed.TimeIncrease(TimeSpan.FromSeconds(5));
    });

Mielőtt megbeszélnénk a szabályzat működését, tekintsük meg működés közben. A helyreállíthatósági szabályzat tesztelése előtt szimulálnia kell egy hibát. Nyissa meg a PingHandler kódot a Receiver projektben, és törölje a sor megjegyzését:

throw new Exception("BOOM");

Most, ha a fogadó kezeli az Ping üzenetet, az sikertelen lesz. Indítsa el újra a megoldást, és nézzük meg, mi történik a Fogadóban.

A kevésbé megbízható PingHandler, minden üzenetünk sikertelen. Láthatja, hogy az újrapróbálkozási szabályzat beindult ezekhez az üzenetekhez. Amikor az első üzenet meghiúsul, a művelet azonnal újrapróbálkozott, legfeljebb háromszor:

Az üzeneteket legfeljebb 3 alkalommal újrapróbálkozó azonnali újrapróbálkozési szabályzatot ábrázoló kép

Természetesen továbbra is sikertelen lesz, így a három azonnali újrapróbálkozás használatakor a késleltetett újrapróbálkozás szabályzata elindul, és az üzenet 5 másodpercig késik:

A késleltetett újrapróbálkozási szabályzatot ábrázoló kép, amely 5 másodperces lépésekben késlelteti az üzeneteket, mielőtt újabb azonnali újrapróbálkozási kísérleteket kísérel meg

Az 5 másodperc leteltét követően az üzenet újrapróbálkozott egy újabb három alkalommal (azaz az azonnali újrapróbálkozási szabályzat újabb iterációjával). Ezek szintén sikertelenek lesznek, és az NServiceBus ismét késlelteti az üzenetet, ezúttal 10 másodpercig, mielőtt újra próbálkozna.

Ha PingHandler a teljes újrapróbálkozási szabályzat futtatása után sem sikerül, az üzenet egy központosított , nevű hibasorba kerül a errorhívás SendFailedMessagesToáltal meghatározott módon.

A sikertelen üzenetet ábrázoló kép

A központosított hibasor fogalma eltér a Azure Service Bus kézbesíthetetlen üzenetsor-kezelési mechanizmusától, amely minden egyes feldolgozási üzenetsorhoz kézbesíthetetlen üzenetsort biztosít. Az NServiceBus esetében a kézbesíthetetlen üzenetek üzenetsorai Azure Service Bus valódi méregüzenet-üzenetsorként működnek, míg a központosított hibasorba végződő üzenetek szükség esetén később újra feldolgozhatók.

Az újrapróbálkozási szabályzat számos olyan hibatípus elhárításában segít, amelyek gyakran átmenetiek vagy részben átmeneti jellegűek. Ez azt jelzi, hogy az ideiglenes hibák gyakran eltűnnek, ha az üzenetet rövid késleltetés után egyszerűen újra feldolgozták. Ilyenek például a hálózati hibák, az adatbázis-zárolások és a külső API-szolgáltatáskimaradások.

Miután egy üzenet bekerült a hibasorba, megvizsgálhatja az üzenet részleteit a választott eszközben, majd eldöntheti, hogy mit tegyen vele. Ha például a ServicePulse-t, egy adott szoftver monitorozási eszközét használja, megtekintheti az üzenet részleteit és a hiba okát:

A ServicePulse-t ábrázoló kép az adott szoftverből

A részletek vizsgálata után visszaküldheti az üzenetet az eredeti üzenetsorba feldolgozás céljából. Ezt megelőzően szerkesztheti is az üzenetet. Ha több üzenet is szerepel a hibasorban, amelyek ugyanazon okból meghiúsultak, azokat kötegként vissza lehet küldeni az eredeti célhelyükre.

Most itt az ideje, hogy kitaláljuk, hol kell üzembe helyezni a megoldást az Azure-ban.

A szolgáltatások üzemeltetésének helye az Azure-ban

Ebben a példában a Küldő és a Fogadó végpontok konzolalkalmazásként való futtatásra vannak konfigurálva. Különböző Azure-szolgáltatásokban is üzemeltethetők, például Azure Functions, Azure-alkalmazás Services, Azure Container Instances, Azure Kubernetes Services és Azure-beli virtuális gépek. Például az alábbi módon konfigurálható a sender végpont Azure-függvényként való futtatásra:

[assembly: FunctionsStartup(typeof(Startup))]
[assembly: NServiceBusEndpointName("Sender")]

public class Startup : FunctionsStartup
{
    public override void Configure(IFunctionsHostBuilder builder)
    {
        builder.UseNServiceBus(() =>
        {
            var configuration = new ServiceBusTriggeredEndpointConfiguration("Sender");
            var transport = configuration.AdvancedConfiguration.Transport;
            transport.Routing().RouteToEndpoint(typeof(Ping), "Receiver");

            return configuration;
        });
    }
}

További információ az NServiceBus függvényekkel való használatáról: Azure Functions és Azure Service Bus az NServiceBus dokumentációjában.

Következő lépések

Az NServiceBus Azure-szolgáltatásokkal való használatáról az alábbi cikkekben talál további információt: