Создание мультитенантных автоматононимных саг

Мы успешно интегрировали нашу стратегию мультиарендности с MassTransit благодаря некоторой помощи Криса Паттерсона. Однако мы спотыкаемся о том, чтобы наши (Автоматонимные) саги были мультитенантными. У меня есть кое-что, что работает, но мне это совсем не нравится. Мы используем стратегию базы данных «схема для каждого клиента», но готовы использовать ее для саги, если это самый простой способ ее решения.

У нас есть идентификатор клиента в заголовке всех сообщений. Мы соскребаем его с IConsumeContext<> входящих сообщений и помещаем обратно в IPublishContext<> исходящих сообщений. Это прекрасно работает с ISagaRepository<>.GetSaga(...), потому что один из его параметров - IConsumeContext<>. Проблема в том, что когда мы вызываем другие ISagaRepository<> методы, у них нет IConsumeContext<>, и у нас нет способа фильтрации по арендатору в репозитории. Если мы будем придерживаться нашей текущей стратегии базы данных, мы знаем клиента, поэтому мы знаем, какую схему использовать. Если мы перейдем к централизованным таблицам арендаторов, мы должны включить арендатора в фильтрацию, потому что объект, с которым он коррелируется, не обязательно уникален для всех арендаторов.

PropertySagaLocator<,> кажется ключевым моментом, исходя из моего текущего понимания. В его Find(IConsumeContext<>) методе у нас есть доступный нам контекст клиента, но он не передается в репозиторий саги.

В моей текущей попытке заставить это работать, я создал локатор саги о свойствах для мультитенантности, который работает со специализированным репозиторием саги о арендаторах и дает ему контекст клиента, необходимый для использования его метода .Where(...) надлежащим образом. Но вот где это становится уродливым. Конкретный класс PropertySagaLocator<,> создается Automatonymous, и поэтому, чтобы поменять его, я должен начать с края Automatonymous, с одного из методов расширения .StateMachineSaga(...), и полностью заменить конкретные классы вплоть до точки, в которой он интегрируется. с MassTransit, используя PropertySagaLocator<,>, поскольку это цепочка конкретных классов, инстанцирующих друг друга на всем пути вниз. Мне неудобно делать такой глубокий разрез через Automatonymous, но мне кажется, что независимо от того, возьмем ли мы стратегию «схема на каждого арендатора» или переключим ее, мы застряли с необходимостью интеграции на этом же этапе.

Другой аспект этого заключается в том, что нам нужно указывать идентификатор клиента в исходящих сообщениях, когда используется нотация .Publish(...) Automatonymous. В настоящее время я делаю это с помощью шаблона декоратора на ServiceBus, и в настоящее время я внедряю декорированную служебную шину для конкретного клиента, когда шина копируется из контекста потребления в состояние экземпляра, т. Е. В мои переопределения метода приемника сообщений саги GetHandlers().

Есть ли у кого-нибудь опыт интеграции автоматических саг с мультитенантностью? То, что мы делаем сейчас, кажется инвазивным, и мы хотели бы найти более естественный шов.


person Keith Pinson    schedule 29.07.2015    source источник
comment
Точки расширения в MT3 (особенно в отношении использования с Automatonymous) намного лучше, поэтому с этим выпуском это, вероятно, станет проще. Схема для каждого клиента - это глубокий подход, но возможность передавать заголовок через цепочку сообщений - это то, что я действительно хотел бы обеспечить, чтобы она хорошо поддерживалась. Я был бы счастлив поработать с вами над этим, чтобы убедиться, что он отвечает вашим потребностям, поскольку я считаю, что ваш вариант использования не уникален.   -  person Chris Patterson    schedule 30.07.2015
comment
@ChrisPatterson привет, спасибо. Я добавил ниже ответ о том, что я изменил, и это намного лучше, но не позволяет мне коррелировать по свойствам.   -  person Keith Pinson    schedule 30.07.2015


Ответы (1)


Я нашел другой подход, который намного менее инвазивен, но более ограничен. В частности, вы не можете использовать PropertySagaLocator, т.е. все ваши корреляции должны быть идентификаторами корреляции путем наследования от интерфейса CorrelatedBy<>. Убедитесь, что вы не выполняете никаких StateMachineSagaRepository<>.Correlate(...) вызовов, потому что, если вы это сделаете, он будет использовать локатор свойств, даже если вы дадите ему фактический идентификатор корреляции.

Что это позволяет мне сделать, так это избегать использования каких-либо методов в репозитории саги, кроме GetSaga(...), где у меня есть контекст, который мне нужен для нашей стратегии мультитенантности. Затем я бросаю NotImplementedByDesignException в другие.

Это оставляет мне только одно, о чем нужно беспокоиться; как получить идентификатор арендатора в заголовках сообщений, исходящих от .Publish(...) звонков. Для этого я просто разделил ConsumeContext<> на подклассы и одновременно реализовал IConsumeContext<>, а затем переопределил свойство Bus на new, чтобы я мог установить на нем шину. Затем у меня был шаблон-декоратор служебной шины, который гарантирует, что шина публикуется с заголовком клиента, независимо от того, какой метод вы для нее вызываете. Затем в своем репозитории саги я обернул возвращаемые мной действия в лямбду, которая передает мой подклассовый контекст потребления вместе с моей декорированной шиной, зависящей от клиента, в потребителя для саги, а не только в прямой контекст потребления. Это приводит к тому, что шина, которая настраивается на состояние саги, является специфическим для этого клиента, и все исходящие сообщения затем имеют идентификатор клиента.

person Keith Pinson    schedule 30.07.2015