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
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ık kullandığınız kod düzenleyicisinde açın
SendReceiveWithNservicebus.sln
(Örneğin, Visual Studio 2022).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ıca
AzureServiceBusTransport
, ü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.ICommand
basit 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 Main
Program.cs
Gö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.json
bir 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ı, SenderWorker
her 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 ExecuteAsync
SenderWorker
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ı PingHandler
bir 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 Ping
bir 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 IMessageHandlerContext
alı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 PongHandler
iç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:
- Çözüm Gezgini'de çözüme sağ tıklayın
- "Başlangıç Projelerini Ayarla..." öğesini seçin
- Birden çok başlangıç projesi seçin
- 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:
- Gönderen projesinde aç
Program.cs
- 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 PingHandler
olan 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:
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:
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ı error
merkezi bir hata kuyruğuna SendFailedMessagesTo
yerleştirilir.
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:
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: