Опитвам се да модифицирам базиран на Azure Video Store примерно приложение, така че предният сайт за електронна търговия да може да се мащабира.
По-конкретно, искам всички екземпляри на уеб сайта да бъдат уведомявани за събития като OrderPlaced, така че без значение към кой уеб сървър уеб приложението на клиента е свързано чрез SignalR, то ще получи правилно известието и ще актуализира потребителския интерфейс.
По-долу е текущата ми конфигурация в Global.asax:
Feature.Disable<TimeoutManager>();
Configure.ScaleOut(s => s.UseUniqueBrokerQueuePerMachine());
startableBus = Configure.With()
.DefaultBuilder()
.TraceLogger()
.UseTransport<AzureServiceBus>()
.PurgeOnStartup(true)
.UnicastBus()
.RunHandlersUnderIncomingPrincipal(false)
.RijndaelEncryptionService()
.CreateBus();
Configure.Instance.ForInstallationOn<Windows>().Install();
bus = startableBus.Start();
И също така конфигурирах опашките на Azure Service Bus, използвайки:
class AzureServiceBusConfiguration : IProvideConfiguration<NServiceBus.Config.AzureServiceBusQueueConfig>
{
public AzureServiceBusQueueConfig GetConfiguration()
{
return new AzureServiceBusQueueConfig()
{
QueuePerInstance = true
};
}
}
Зададох уеб ролята да мащабира до два екземпляра и както се очакваше, се създават две опашки (ecommerce и ecommerce-1). Не виждам обаче да се създават допълнителни абонаменти за теми под темата videostore.sales.events. Вместо това виждам:
Предполагам, че ще видите абонаменти за VideoStore.ECommerce-1.OrderCancelled и VideoStore.ECommerce-1.OrderPlaced под темата Videostore.Sales.Events. Или не се съхраняват така абонаментите при използване на Azure Service Bus?
Какво ми липсва тук? Получавам събитието на един от случаите на електронна търговия, но никога и на двата. Дори ако това не е правилният начин за мащабиране на SignalR, моят случай на използване се простира до неща като обезсилване на кеша.
Също така намирам за странно, че се създават две опашки за грешки и одит. Защо би се случило това?
АКТУАЛИЗАЦИЯ
Ив е прав. AzureServiceBusSubscriptionNamingConvention не прилагаше правилното индивидуализирано име. Успях да поправя това, като внедрих следния EndpointConfig:
namespace VideoStore.ECommerce
{
public class EndpointConfig : IConfigureThisEndpoint, IWantCustomInitialization
{
public void Init()
{
AzureServiceBusSubscriptionNamingConvention.Apply = BuildSubscriptionName;
AzureServiceBusSubscriptionNamingConvention.ApplyFullNameConvention = BuildSubscriptionName;
}
private static string BuildSubscriptionName(Type eventType)
{
var subscriptionName = eventType != null ? Configure.EndpointName + "." + eventType.Name : Configure.EndpointName;
if (subscriptionName.Length >= 50)
subscriptionName = new DeterministicGuidBuilder().Build(subscriptionName).ToString();
if (!SettingsHolder.GetOrDefault<bool>("ScaleOut.UseSingleBrokerQueue"))
subscriptionName = Individualize(subscriptionName);
return subscriptionName;
}
public static string Individualize(string queueName)
{
var parser = new ConnectionStringParser();
var individualQueueName = queueName;
if (SafeRoleEnvironment.IsAvailable)
{
var index = parser.ParseIndexFrom(SafeRoleEnvironment.CurrentRoleInstanceId);
var currentQueue = parser.ParseQueueNameFrom(queueName);
if (!currentQueue.EndsWith("-" + index.ToString(CultureInfo.InvariantCulture))) //individualize can be applied multiple times
{
individualQueueName = currentQueue
+ (index > 0 ? "-" : "")
+ (index > 0 ? index.ToString(CultureInfo.InvariantCulture) : "");
}
if (queueName.Contains("@"))
individualQueueName += "@" + parser.ParseNamespaceFrom(queueName);
}
return individualQueueName;
}
}
}
Не можах обаче да накарам NServiceBus да разпознае моя клас EndpointConfig. Вместо това трябваше да го извикам ръчно, преди да пусна автобуса. От моя Global.asax.cs:
new EndpointConfig().Init();
bus = startableBus.Start();
След като направих това, имената на абонамента се появиха според очакванията:
Не знам защо игнорира моя IConfigureThisEndpoint, но това работи.