Абонаментите за събития на NServiceBus не работят с Azure Service Bus

Опитвам се да модифицирам базиран на 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, но това работи.


person RMD    schedule 04.06.2014    source източник


Отговори (1)


Това звучи като грешка, можете ли да повдигнете проблем с github по този въпрос на https://github.com/Particular/NServiceBus.Azure

Въпреки това мисля, че е по-добре да се използва функцията за мащабиране на signalr, вместо да се използва QueuePerInstance, тъй като signalr трябва да репликира друга информация като (съпоставяне на връзка/група) вътрешно, когато работи в режим на мащабиране.

Актуализация:

Мисля, че виждам проблема, абонаментите също трябва да бъдат индивидуализирани, което не е така в настоящите конвенции за именуване

https://github.com/Particular/NServiceBus.Azure/blob/master/src/NServiceBus.Azure.Transports.WindowsAzureServiceBus/NamingConventions/AzureServiceBusSubscriptionNamingConvention.cs

докато е в конвенциите за зареждане на опашка

https://github.com/Particular/NServiceBus.Azure/blob/master/src/NServiceBus.Azure.Transports.WindowsAzureServiceBus/NamingConventions/AzureServiceBusQueueNamingConvention.cs#L27

Тъй като тези конвенции са публични, можете да ги замените, за да заобиколите проблема, като промените функцията в IWantCustomInitialization, докато мога да получа корекция, просто копирайте текущия метод и добавете логиката на индивидуализатора. Индивидуализаторът на опашката обаче е вътрешен, така че ще трябва да копирате този клас от

https://github.com/Particular/NServiceBus.Azure/blob/master/src/NServiceBus.Azure.Transports.WindowsAzureServiceBus/Config/QueueIndividualizer.cs

person Yves Goeleven    schedule 05.06.2014
comment
Ще добавя грешката, но какво да кажем за сценарии, при които правя нещо като анулиране на кеша? В такъв случай QueuePerInstance е точно това, от което се нуждая, нали? Този проблем специфичен ли е за работа в Azure? - person RMD; 05.06.2014
comment
YVes - оказа се, че проблемът не е в именуването на опашката. Вместо това мисля, че може да има проблем с абонаментите за събития. Ревизирам публикацията си и затварям проблема с github. - person RMD; 18.06.2014
comment
Ревизирах публикацията по-горе. някакви мисли? - person RMD; 18.06.2014
comment
Актуализирах оригиналния си отговор (няма достатъчно място тук) - person Yves Goeleven; 18.06.2014
comment
Това има смисъл. Всъщност започнах по този път. В кои проекти трябва да се прилага тази конвенция? От това, което прочетох, обикновено се изпраща съобщение от абоната до издателя и след това издателят записва абоната. В този случай абонатът ли е този, който сам създава абонамента за темата, тъй като съобщенията са с посредничество? - person RMD; 18.06.2014
comment
Да, абонатът го създава сам. Така че трябва да зададете променената конвенция в крайните точки за абониране. - person Yves Goeleven; 18.06.2014
comment
Благодаря - това реши проблема, но ако видите моята актуализация по-горе, все още имам 2 неразрешени проблема. Първо, EndpointConfig в уеб ролята не се извиква. Трябваше ръчно да го извикам. Второ, все още създава грешка и опашка за одит с наставка върху нея, което подозирам, че не трябва да се случва. - person RMD; 18.06.2014
comment
Това, че конфигурацията на крайната точка не се извиква, е нормално, това е част от хост процеса, но вие стартирате всичко ръчно в уеброля - person Yves Goeleven; 18.06.2014
comment
Трябва да разгледам опашката за одит, това е очаквано поведение, тъй като сте му казали да създава опашки за екземпляр, но може би това не е желано поведение... - person Yves Goeleven; 18.06.2014
comment
Подозирам, че това не е желаното поведение - особено ако ServiceControl разчита на тези опашки. Дали? - person RMD; 19.06.2014
comment
Относно цялото нещо с невалидността на кеша - не използвайте NServiceBus заедно с кеширане в процеса, за да внедрите свой собствен разпределен кеш. Ако имате нужда от разпределен кеш, изберете такъв, който вече съществува. - person Udi Dahan; 21.12.2014
comment
@UdiDahan – Знам откъде идваш, но в този случай работим добре. Проста обвивка около MemoryCache, която обезсилва кешираните групи елементи, когато получават събития от NSB. Имаме някои изисквания, свързани с HIPAA, които ни пречат да използваме много от разпределените кешове на третата част там. - person RMD; 10.01.2015