Aracılığıyla paylaş


NServiceBus ve Azure Service Bus ile ileti temelli iş uygulamaları oluşturma

NServiceBus, Belirli Yazılımlar tarafından sağlanan ticari bir mesajlaşma çerçevesidir. Azure Service Bus'ın üzerine kurulmuştur ve altyapı sorunlarını soyutlayarak geliştiricilerin iş mantığına odaklanmalarına yardımcı olur. Bu kılavuzda, iki hizmet arasında ileti alışverişi sağlayan bir çözüm oluşturacağız. Ayrıca başarısız iletileri otomatik olarak yeniden denemeyi ve bu hizmetleri Azure'da barındırma seçeneklerini gözden geçirmeyi de göstereceğiz.

Not

Bu öğreticinin kodu Belirli Yazılım Belgeleri web sitesinde bulunur.

Önkoşullar

Örnekte bir Azure Service Bus ad alanı oluşturduğunuz varsayılır.

Önemli

NServiceBus için en az Standart katman gerekir. Temel katman çalışmaz.

Çözümü indirme ve hazırlama

  1. Kodu Belirli Yazılım Belgeleri web sitesinden indirin. Çözüm SendReceiveWithNservicebus.sln üç projeden oluşur:

    • Gönderen: İleti gönderen konsol uygulaması
    • Alıcı: Gönderenden ileti alan ve geri yanıtlayan bir konsol uygulaması
    • Paylaşılan: Gönderen ve alıcı arasında paylaşılan ileti sözleşmelerini içeren bir sınıf kitaplığı

    Belirli Bir Yazılımdan alınan bir görselleştirme ve hata ayıklama aracı olan ServiceInsight tarafından oluşturulan aşağıdaki diyagramda ileti akışı gösterilmektedir:

    Sıralı diyagramı gösteren resim

  2. Sık kullandığınız kod düzenleyicisinde açın SendReceiveWithNservicebus.sln (Örneğin, Visual Studio 2022).

  3. Alıcı ve Gönderen projelerinde açın appsettings.json ve Azure Service Bus ad alanınızın bağlantı dizesi olarak ayarlayınAzureServiceBusConnectionString.

    • Bu, Azure portalında Service Bus Ad Alanı>Ayarları>Paylaşılan erişim ilkeleri>RootManageSharedAccessKey>Birincil Bağlantı Dizesi altında bulunabilir.
    • ayrıcaAzureServiceBusTransport, üretim ortamında daha güvenli olacak bir ad alanı ve belirteç kimlik bilgilerini kabul eden bir oluşturucuya sahiptir, ancak bu öğreticinin amaçları doğrultusunda paylaşılan erişim anahtarı bağlantı dizesi kullanılacaktır.

Paylaşılan ileti sözleşmelerini tanımlama

Paylaşılan sınıf kitaplığı, iletilerimizi göndermek için kullanılan sözleşmeleri tanımladığınız yerdir. İletilerimizi tanımlamak için NServiceBus kullanabileceğiniz arabirimleri içeren NuGet paketine bir başvuru içerir. Arabirimler gerekli değildir, ancak bize NServiceBus'tan fazladan doğrulama sağlar ve kodun kendi kendine belgelenmesine izin verir.

İlk olarak sınıfı gözden geçireceğiz Ping.cs

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

sınıfı, Ping Gönderenin Alıcıya gönderdiği bir iletiyi tanımlar. NServiceBus paketinden bir arabirim uygulayan NServiceBus.ICommandbasit bir C# sınıfıdır. Bu ileti, okuyucuya ve NServiceBus'a bunun bir komut olduğunu belirten bir sinyaldir, ancak arabirimleri kullanmadan iletileri tanımlamanın başka yolları da vardır.

Paylaşılan projelerdeki diğer ileti sınıfı:Pong.cs

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

Pong aynı zamanda basit bir C# nesnesidir, ancak bu nesne uygular NServiceBus.IMessage. IMessage Arabirim, ne komut ne de olay olan genel bir iletiyi temsil eder ve genellikle yanıtlar için kullanılır. Örneğimizde, bir iletinin alındığını belirtmek için Alıcı'nın Gönderene geri gönderdiği bir yanıttır.

Ping vePong, kullanacağınız iki ileti türü olur. Sonraki adım, Göndereni Azure Service Bus kullanacak ve ileti Ping gönderecek şekilde yapılandırmaktır.

Göndereni ayarlama

Gönderen, iletimizi Ping gönderen bir uç noktadır. Burada Gönderen'i aktarım mekanizması olarak Azure Service Bus kullanacak şekilde yapılandıracak, ardından bir Ping örnek oluşturup gönderebilirsiniz.

yönteminde MainProgram.csGönderen uç noktasını yapılandıracaksınız:

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

Burada paketi açmak için çok fazla şey var, bu nedenle adım adım gözden geçireceğiz.

Uç nokta için konak yapılandırma

Barındırma ve günlüğe kaydetme, standart Microsoft Genel Konak seçenekleri kullanılarak yapılandırılır. Şimdilik uç nokta bir konsol uygulaması olarak çalışacak şekilde yapılandırılmıştır, ancak bu makalenin devamında ele alacağımız en az değişiklikle Azure İşlevleri içinde çalıştırılacak şekilde değiştirilebilir.

NServiceBus uç noktasını yapılandırma

Ardından, konağa uzantı yöntemiyle .UseNServiceBus(…) NServiceBus kullanmasını söylersiniz. yöntemi, konak çalıştırıldığında başlatılacak bir uç nokta döndüren bir geri çağırma işlevi alır.

Uç nokta yapılandırmasında, aktarım için öğesini belirterek AzureServiceBus içinden appsettings.jsonbir bağlantı dizesi sağlarsınız. Ardından, yönlendirmeyi ayarlayarak türdeki Ping iletilerin "Alıcı" adlı bir uç noktaya gönderilmesini sağlarsınız. NServiceBus'un alıcının adresine gerek kalmadan iletiyi hedefe gönderme işlemini otomatikleştirmesine olanak tanır.

çağrısı EnableInstallers , uç nokta başlatıldığında Azure Service Bus ad alanında topolojimizi ayarlar ve gerektiğinde gerekli kuyrukları oluşturur. Üretim ortamlarında operasyonel betik oluşturma, topolojiyi oluşturmaya yönelik bir diğer seçenektir.

İleti göndermek için arka plan hizmetini ayarlama

Gönderenin son parçası, SenderWorkerher saniye bir ileti gönderecek şekilde yapılandırılmış bir Ping arka plan hizmetidir.

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

IMessageSession içinde ExecuteAsyncSenderWorker kullanılan eklenir ve bir ileti işleyicisi dışında NServiceBus kullanarak ileti göndermemize olanak tanır. içinde Sender yapılandırdığınız yönlendirme, iletilerin hedefini Ping belirtir. Sistemin topolojisini (hangi iletilerin hangi adreslere yönlendirildiği) iş kodundan ayrı bir sorun olarak tutar.

Gönderen uygulaması da içerir PongHandler. Alıcı'yı tartıştıktan sonra ona geri dönersiniz. Bundan sonra bunu yapacağız.

Alıcıyı ayarlama

Alıcı, bir iletiyi dinleyen, bir Ping ileti alındığında günlüğe kaydeden ve gönderene geri yanıt veren bir uç noktadır. Bu bölümde, Gönderen'e benzeyen uç nokta yapılandırmasını hızla gözden geçirecek ve ardından dikkatimizi ileti işleyicisine çevireceğiz.

Gönderen gibi, Microsoft Genel Ana Bilgisayarı'nı kullanarak alıcıyı bir konsol uygulaması olarak ayarlayın. Gönderenden ayırmak için aynı günlük ve uç nokta yapılandırmasını (ileti aktarımı olarak Azure Service Bus ile birlikte) ancak farklı bir adla kullanır:

var endpointConfiguration = new EndpointConfiguration("Receiver");

Bu uç nokta yalnızca gönderene yanıt verdiği ve yeni konuşmalar başlatmadığı için yönlendirme yapılandırması gerekmez. Ayrıca yalnızca bir ileti aldığında yanıt verdiği için Gönderen gibi bir arka plan çalışanına da ihtiyacı yoktur.

Ping iletisi işleyicisi

Alıcı projesi adlı PingHandlerbir ileti işleyicisi içerir:

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

Açıklamalı kodu şimdilik yoksayalım; daha sonra hatadan kurtarma hakkında konuştuğumuzda geri döneceğiz.

sınıfı, bir yöntemi tanımlayan öğesini uygular IHandleMessages<Ping>: Handle. Bu arabirim NServiceBus'a uç nokta türünde Pingbir ileti aldığında bu işleyicideki Handle yöntemi tarafından işlenmesi gerektiğini bildirir. yöntemi, Handle iletinin kendisini bir parametre ve yanıt verme, komut gönderme veya olayları yayımlama gibi daha fazla mesajlaşma işlemine olanak tanıyan bir IMessageHandlerContextalır.

Bizim PingHandler işimiz basittir: bir Ping ileti alındığında, ileti ayrıntılarını günlüğe kaydedip gönderene daha sonra Gönderen'in PongHandleriçinde işlenen yeni Pong bir iletiyle yanıtlayın.

Not

Gönderenin yapılandırmasında, iletilerin Ping Alıcıya yönlendirilmesi gerektiğini belirttiniz. NServiceBus iletiye meta veriler ekler ve iletinin kaynağını belirtir. Bu nedenle, yanıt iletisi için herhangi bir yönlendirme verisi Pong belirtmeniz gerekmez; otomatik olarak kaynağı olan Gönderen'e yönlendirilir.

Hem Gönderen hem de Alıcı düzgün yapılandırıldığında, artık çözümü çalıştırabilirsiniz.

Çözümü çalıştırın

Çözümü başlatmak için hem Göndereni hem de Alıcı'yı çalıştırmanız gerekir. Visual Studio Code kullanıyorsanız "Tümünde Hata Ayıkla" yapılandırmasını başlatın. Visual Studio kullanıyorsanız, çözümü hem Gönderen hem de Alıcı projelerini başlatacak şekilde yapılandırın:

  1. Çözüm Gezgini'de çözüme sağ tıklayın
  2. "Başlangıç Projelerini Ayarla..." öğesini seçin
  3. Birden çok başlangıç projesi seçin
  4. Hem Gönderen hem de Alıcı için açılan listeden "Başlat"ı seçin

Çözümü başlatın. Biri Gönderen ve diğeri Alıcı için olan iki konsol uygulaması görüntülenir.

Gönderen'de, arka plan işi sayesinde her saniye bir Ping ileti gönderildiğine SenderWorker dikkat edin. Alıcı, aldığı her Ping iletinin ayrıntılarını görüntüler ve Gönderen yanıtta aldığı her Pong iletinin ayrıntılarını günlüğe kaydeder.

Artık her şey yolunda olduğuna göre, hadi kıralım.

Dayanıklılık çalışır durumda

Hatalar, yazılım sistemlerindeki yaşamın bir gerçeğidir. Kodun başarısız olması kaçınılmazdır ve ağ hataları, veritabanı kilitleri, üçüncü taraf API'deki değişiklikler ve düz eski kodlama hataları gibi çeşitli nedenlerle bunu yapabilir.

NServiceBus, hataları işlemek için sağlam kurtarılabilirlik özelliklerine sahiptir. İleti işleyicisi başarısız olduğunda, iletiler önceden tanımlanmış bir ilkeye göre otomatik olarak yeniden denener. İki tür yeniden deneme ilkesi vardır: anında yeniden denemeler ve gecikmeli yeniden denemeler. Nasıl çalıştıklarını açıklamanın en iyi yolu, onları çalışır durumda görmektir. Alıcı uç noktamıza bir yeniden deneme ilkesi ekleyelim:

  1. Gönderen projesinde aç Program.cs
  2. Satırın .EnableInstallers arkasına aşağıdaki kodu ekleyin:
endpointConfiguration.SendFailedMessagesTo("error");
var recoverability = endpointConfiguration.Recoverability();
recoverability.Immediate(
    immediate =>
    {
        immediate.NumberOfRetries(3);
    });
recoverability.Delayed(
    delayed =>
    {
        delayed.NumberOfRetries(2);
        delayed.TimeIncrease(TimeSpan.FromSeconds(5));
    });

Bu ilkenin nasıl çalıştığını tartışmadan önce bunu çalışır durumda görelim. Kurtarılabilirlik ilkesini test etmeden önce bir hata benzetimi yapmanız gerekir. PingHandler Alıcı projesinde kodu açın ve şu satırın açıklamasını kaldırın:

throw new Exception("BOOM");

Alıcı bir Ping iletiyi işlediğinde başarısız olur. Çözümü yeniden başlatın ve Alıcı'da neler olduğunu görelim.

Daha az güvenilir PingHandlerolan tüm iletilerimiz başarısız olur. Bu iletiler için yeniden deneme ilkesinin devreye giriyor olduğunu görebilirsiniz. bir ileti ilk kez başarısız olduğunda hemen üç kez yeniden denenecek:

İletileri en fazla 3 kez yeniden deneyen hemen yeniden deneme ilkesini gösteren görüntü

Tabii ki başarısız olacak, bu nedenle üç anlık yeniden deneme kullanıldığında gecikmeli yeniden deneme ilkesi başlatılır ve ileti 5 saniye gecikir:

Başka bir anlık yeniden deneme denemesi denemeden önce iletileri 5 saniyelik artışlarla geciktiren gecikmeli yeniden deneme ilkesini gösteren görüntü

Bu 5 saniye geçtikten sonra, ileti üç kez daha yeniden denenecektir (yani, hemen yeniden deneme ilkesinin başka bir yinelemesi). Bunlar da başarısız olur ve NServiceBus yeniden denemeden önce iletiyi 10 saniye boyunca yeniden geciktirecektir.

PingHandler Tam yeniden deneme ilkesi çalıştırıldıktan sonra yine de başarılı olmazsa, ileti çağrısı tarafından tanımlandığı gibi adlı errormerkezi bir hata kuyruğuna SendFailedMessagesToyerleştirilir.

Başarısız iletiyi gösteren resim

Merkezi hata kuyruğu kavramı, Azure Service Bus'ta her işlem kuyruğu için bir teslim edilemeyen ileti kuyruğu olan teslim edilemeyen ileti mekanizmasından farklıdır. NServiceBus ile Azure Service Bus'taki teslim edilemeyen kuyruklar gerçek zehirli ileti kuyrukları görevi görürken, merkezi hata kuyruğuna giden iletiler gerekirse daha sonra yeniden işlenebilir.

Yeniden deneme ilkesi, genellikle geçici veya yarı geçici olan çeşitli hata türlerinin giderilmesine yardımcı olur. Başka bir ifadeyle, ileti kısa bir gecikmeden sonra yeniden işlendiğinde geçici olan ve genellikle ortadan kaldırılan hatalar. Örnek olarak ağ hataları, veritabanı kilitleri ve üçüncü taraf API kesintileri verilebilir.

bir ileti hata kuyruğuna girdikten sonra, istediğiniz araçta ileti ayrıntılarını inceleyebilir ve ardından iletiyle ne yapacağınıza karar vekleyebilirsiniz. Örneğin, Belirli Yazılım tarafından kullanılan bir izleme aracı olan ServicePulse'ı kullanarak ileti ayrıntılarını ve hatanın nedenini görüntüleyebiliriz:

Belirli Bir Yazılımdan ServicePulse'ı gösteren görüntü

Ayrıntıları inceledikten sonra, iletiyi işlenmek üzere özgün kuyruğuna geri gönderebilirsiniz. Bunu yapmadan önce iletiyi de düzenleyebilirsiniz. Hata kuyruğunda aynı nedenle başarısız olan birden çok ileti varsa, bunların tümü özgün hedeflerine toplu iş olarak geri gönderilebilir.

Şimdi çözümümüzü Azure'da nereye dağıtabileceğinizi öğrenmenin zamanı geldi.

Azure'da hizmetlerin barındırıldığı yer

Bu örnekte, Gönderen ve Alıcı uç noktaları konsol uygulamaları olarak çalışacak şekilde yapılandırılır. Bunlar Azure İşlevleri, Azure Uygulaması Hizmetleri, Azure Container Instances, Azure Kubernetes Services ve Azure VM'leri gibi çeşitli Azure hizmetlerinde de barındırılabilir. Örneğin, Gönderen uç noktası bir Azure İşlevi olarak çalışacak şekilde şu şekilde yapılandırılabilir:

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

İşlevler ile NServiceBus kullanma hakkında daha fazla bilgi için NServiceBus belgelerindeki Azure Service Bus ile Azure İşlevleri bölümüne bakın.

Sonraki adımlar

NServiceBus'ı Azure hizmetleriyle kullanma hakkında daha fazla bilgi için aşağıdaki makalelere bakın: