protected UsingInitializedSagaStore() { SagaId = GuidStrategy.NewGuid(); SagaContext = new SagaContext(typeof(FakeSaga), SagaId, new FakeEvent()); TypeLocator.Setup(mock => mock.GetTypes(It.IsAny <Func <Type, Boolean> >())).Returns(new[] { typeof(FakeSaga) }); SagaStore = new SqlSagaStore(Dialect, Serializer, TypeLocator.Object); SagaStore.Purge(); }
/// <summary> /// Initializes a new instance of <see cref="SagaTimeoutCache"/>. /// </summary> /// <param name="sagaStore">The saga store used to retrieve pending saga timeouts.</param> /// <param name="timeoutCacheDuration">The maximum cache duration for a given saga timeout (5 minute minimum).</param> public SagaTimeoutCache(IStoreSagas sagaStore, TimeSpan timeoutCacheDuration) { Verify.NotNull(sagaStore, nameof(sagaStore)); this.sagaStore = sagaStore; this.maximumCachedTimeout = DateTime.MinValue; this.timeoutCacheDuration = timeoutCacheDuration < MinimumCacheDuration ? MinimumCacheDuration : timeoutCacheDuration; }
protected UsingInitializedSagaStore() { SagaId = GuidStrategy.NewGuid(); SagaContext = new SagaContext(typeof(FakeSaga), SagaId, new FakeEvent()); TypeLocator.Setup(mock => mock.GetTypes(It.IsAny<Func<Type, Boolean>>())).Returns(new[] { typeof(FakeSaga) }); SagaStore = new SqlSagaStore(Dialect, Serializer, TypeLocator.Object); SagaStore.Purge(); }
/// <summary> /// Initializes a new instance of <see cref="HookableSagaStore"/> with <paramref name="pipelineHooks"/> safe to enumerate multiple times. /// </summary> /// <param name="sagaStore">The underlying <see cref="IStoreSagas"/> implementation to be decorated.</param> /// <param name="pipelineHooks">The set of zero or more <see cref="PipelineHook"/> implementations used to extend <see cref="IStoreSagas"/> behavior.</param> private HookableSagaStore(IStoreSagas sagaStore, IList<PipelineHook> pipelineHooks) { Verify.NotNull(sagaStore, nameof(sagaStore)); this.sagaStore = sagaStore; this.preGetHooks = pipelineHooks.Where(pipelineHook => pipelineHook.ImplementsPreGet).ToArray(); this.postGetHooks = pipelineHooks.Where(pipelineHook => pipelineHook.ImplementsPostGet).Reverse().ToArray(); this.preSaveHooks = pipelineHooks.Where(pipelineHook => pipelineHook.ImplementsPreSave).ToArray(); this.postSaveHooks = pipelineHooks.Where(pipelineHook => pipelineHook.ImplementsPostSave).Reverse().ToArray(); }
/// <summary> /// Initializes a new instance of <see cref="HookableSagaStore"/> with <paramref name="pipelineHooks"/> safe to enumerate multiple times. /// </summary> /// <param name="sagaStore">The underlying <see cref="IStoreSagas"/> implementation to be decorated.</param> /// <param name="pipelineHooks">The set of zero or more <see cref="PipelineHook"/> implementations used to extend <see cref="IStoreSagas"/> behavior.</param> private HookableSagaStore(IStoreSagas sagaStore, IList <PipelineHook> pipelineHooks) { Verify.NotNull(sagaStore, nameof(sagaStore)); this.sagaStore = sagaStore; this.preGetHooks = pipelineHooks.Where(pipelineHook => pipelineHook.ImplementsPreGet).ToArray(); this.postGetHooks = pipelineHooks.Where(pipelineHook => pipelineHook.ImplementsPostGet).Reverse().ToArray(); this.preSaveHooks = pipelineHooks.Where(pipelineHook => pipelineHook.ImplementsPreSave).ToArray(); this.postSaveHooks = pipelineHooks.Where(pipelineHook => pipelineHook.ImplementsPostSave).Reverse().ToArray(); }
/// <summary> /// Initializes a new instance of <see cref="CachedSagaStore"/> using the specified <paramref name="slidingExpiration"/>. /// </summary> /// <param name="sagaStore">The underlying <see cref="IStoreSagas"/> implementation to be decorated.</param> /// <param name="slidingExpiration">The maximum time an <see cref="Saga"/> may existing in the cache without being accessed.</param> /// <param name="memoryCache">The underlying cache implementation.</param> internal CachedSagaStore(IStoreSagas sagaStore, TimeSpan slidingExpiration, MemoryCache memoryCache) { Verify.NotNull(sagaStore, nameof(sagaStore)); Verify.NotNull(memoryCache, nameof(memoryCache)); Verify.GreaterThanOrEqual(TimeSpan.FromSeconds(1), slidingExpiration, nameof(sagaStore)); this.sagaStore = sagaStore; this.memoryCache = memoryCache; this.slidingExpiration = slidingExpiration; }
/// <summary> /// Initializes a new instance of <see cref="SagaEventHandler"/>. /// </summary> /// <param name="eventHandler">The base event handler to decorate.</param> /// <param name="sagaMetadata">The saga metadata associated with this saga event handler.</param> /// <param name="sagaStore">The saga store used to load/save saga state.</param> /// <param name="commandPublisher">The command publisher used to publish saga commands.</param> /// <param name="settings">The event processor settings.</param> internal SagaEventHandler(EventHandler eventHandler, SagaMetadata sagaMetadata, IStoreSagas sagaStore, Lazy <IPublishCommands> commandPublisher, IStoreSagaSettings settings) : base(eventHandler) { Verify.NotNull(sagaStore, nameof(sagaStore)); Verify.NotNull(sagaMetadata, nameof(sagaMetadata)); Verify.NotNull(commandPublisher, nameof(commandPublisher)); Verify.NotNull(settings, nameof(settings)); this.sagaStore = sagaStore; this.sagaMetadata = sagaMetadata; this.lazyCommandPublisher = commandPublisher; }
/// <summary> /// Initializes a new instance of <see cref="SagaEventHandler"/>. /// </summary> /// <param name="eventHandler">The base event handler to decorate.</param> /// <param name="sagaMetadata">The saga metadata associated with this saga event handler.</param> /// <param name="sagaStore">The saga store used to load/save saga state.</param> /// <param name="commandPublisher">The command publisher used to publish saga commands.</param> /// <param name="settings">The event processor settings.</param> internal SagaEventHandler(EventHandler eventHandler, SagaMetadata sagaMetadata, IStoreSagas sagaStore, Lazy<IPublishCommands> commandPublisher, IStoreSagaSettings settings) : base(eventHandler) { Verify.NotNull(sagaStore, nameof(sagaStore)); Verify.NotNull(sagaMetadata, nameof(sagaMetadata)); Verify.NotNull(commandPublisher, nameof(commandPublisher)); Verify.NotNull(settings, nameof(settings)); this.sagaStore = sagaStore; this.sagaMetadata = sagaMetadata; this.lazyCommandPublisher = commandPublisher; }
/// <summary> /// Initializes a new instance of <see cref="EventHandlerRegistry"/> with the specified <paramref name="typeLocator"/> and <paramref name="serviceProvider"/>. /// </summary> /// <param name="sagaStore">The saga store to pass on to any <see cref="SagaEventHandler"/> instances.</param> /// <param name="typeLocator">The type locator used to retrieve all known <see cref="Event"/> types.</param> /// <param name="serviceProvider">The service locator used to retrieve singleton event handler dependencies.</param> /// <param name="commandPublisher">The command publisher used to publish saga commands.</param> public EventHandlerRegistry(ILocateTypes typeLocator, IServiceProvider serviceProvider, IStoreSagas sagaStore, Lazy<IPublishCommands> commandPublisher) { Verify.NotNull(sagaStore, nameof(sagaStore)); Verify.NotNull(typeLocator, nameof(typeLocator)); Verify.NotNull(serviceProvider, nameof(serviceProvider)); Verify.NotNull(commandPublisher, nameof(commandPublisher)); knownEventHandlers = DiscoverEventHandlers(typeLocator, serviceProvider, sagaStore, commandPublisher); knownSagaTimeoutHandlers = knownEventHandlers.Where(item => typeof(Timeout).IsAssignableFrom(item.Key)) .SelectMany(item => item.Value) .OfType<SagaEventHandler>() .Distinct(item => item.HandlerType) .ToDictionary(item => item.HandlerType, item => new EventHandler[] { item }); }
/// <summary> /// Discover all event handlers methods associated with any locatable class marked with with <see cref="EventHandlerAttribute"/>. /// </summary> /// <param name="sagaStore">The saga store to pass on to any <see cref="SagaEventHandler"/> instances.</param> /// <param name="typeLocator">The type locator use to retrieve all known classes marked with <see cref="EventHandlerAttribute"/>.</param> /// <param name="serviceProvider">The service locator used to retrieve singleton event handler dependencies.</param> /// <param name="commandPublisher">The command publisher used to publish saga commands.</param> private static Dictionary <Type, List <EventHandler> > DiscoverHandleMethods(ILocateTypes typeLocator, IServiceProvider serviceProvider, IStoreSagas sagaStore, Lazy <IPublishCommands> commandPublisher) { var handlerTypes = typeLocator.GetTypes(type => !type.IsAbstract && type.IsClass && type.GetCustomAttribute <EventHandlerAttribute>() != null); var knownEventHandlers = new Dictionary <Type, List <EventHandler> >(); foreach (var handlerType in handlerTypes) { var handleMethods = GetHandleMethods(handlerType, serviceProvider); var sagaMetadata = typeof(Saga).IsAssignableFrom(handlerType) ? GetSagaMetadata(handlerType, handleMethods) : null; foreach (var handleMethod in handleMethods) { List <EventHandler> eventHandlers; Type eventType = handleMethod.Key; if (!knownEventHandlers.TryGetValue(eventType, out eventHandlers)) { knownEventHandlers.Add(eventType, eventHandlers = new List <EventHandler>()); } var eventHandler = new EventHandler(handlerType, eventType, handleMethod.Value, GetHandlerFactory(handlerType, serviceProvider)); if (sagaMetadata != null) { eventHandler = eventType == typeof(Timeout) ? new SagaTimeoutHandler(eventHandler, sagaMetadata, sagaStore, commandPublisher) : new SagaEventHandler(eventHandler, sagaMetadata, sagaStore, commandPublisher); } eventHandlers.Add(eventHandler); } } return(knownEventHandlers); }
/// <summary> /// Initializes a new instance of <see cref="SagaEventHandler"/>. /// </summary> /// <param name="eventHandler">The base event handler to decorate.</param> /// <param name="sagaMetadata">The saga metadata associated with this saga event handler.</param> /// <param name="sagaStore">The saga store used to load/save saga state.</param> /// <param name="commandPublisher">The command publisher used to publish saga commands.</param> internal SagaEventHandler(EventHandler eventHandler, SagaMetadata sagaMetadata, IStoreSagas sagaStore, Lazy<IPublishCommands> commandPublisher) : this(eventHandler, sagaMetadata, sagaStore, commandPublisher, Settings.SagaStore) { }
/// <summary> /// Initalizes a new isntance of <see cref="BenchmarkedSagaStore"/>. /// </summary> /// <param name="sagaStore">The saga store to decorate.</param> /// <param name="statistics">The statistics class.</param> public BenchmarkedSagaStore(IStoreSagas sagaStore, Statistics statistics) { this.sagaStore = sagaStore; this.statistics = statistics; }
/// <summary> /// Initializes a new instance of <see cref="CachedSagaStore"/>. /// </summary> /// <param name="sagaStore">The underlying <see cref="IStoreSagas"/> implementation to be decorated.</param> public CachedSagaStore(IStoreSagas sagaStore) : this(sagaStore, Settings.SagaStore.CacheSlidingExpiration, new MemoryCache("SagaCache")) { }
/// <summary> /// Discover all event handlers associated with any locatable class marked with <see cref="EventHandlerAttribute"/>. /// </summary> /// <param name="sagaStore">The saga store to pass on to any <see cref="SagaEventHandler"/> instances.</param> /// <param name="typeLocator">The type locator use to retrieve all known classes marked with <see cref="EventHandlerAttribute"/>.</param> /// <param name="serviceProvider">The service locator used to retrieve singleton event handler dependencies.</param> /// <param name="commandPublisher">The command publisher used to publish saga commands.</param> private static Dictionary<Type, EventHandler[]> DiscoverEventHandlers(ILocateTypes typeLocator, IServiceProvider serviceProvider, IStoreSagas sagaStore, Lazy<IPublishCommands> commandPublisher) { var knownEvents = typeLocator.GetTypes(type => !type.IsAbstract && type.IsClass && type.DerivesFrom(typeof(Event))); var knownHandlers = DiscoverHandleMethods(typeLocator, serviceProvider, sagaStore, commandPublisher); var result = new Dictionary<Type, EventHandler[]>(); var logMessage = new StringBuilder(); logMessage.AppendLine("Discovered event handlers:"); foreach (var eventType in knownEvents.OrderBy(type => type.FullName)) { var eventHandlers = eventType.GetTypeHierarchy().Reverse() .Where(knownHandlers.ContainsKey) .SelectMany(type => knownHandlers[type]) .OrderBy(handler => handler is SagaEventHandler) .ThenBy(handler => handler.HandlerType.AssemblyQualifiedName) .ToArray(); logMessage.Append(" "); logMessage.Append(eventType); logMessage.AppendLine(); foreach (var eventHandler in eventHandlers) { logMessage.Append(" "); logMessage.Append(eventHandler.HandlerType); logMessage.AppendLine(); } result.Add(eventType, eventHandlers); } Log.Debug(logMessage.ToString); return result; }
/// <summary> /// Discover all event handlers methods associated with any locatable class marked with with <see cref="EventHandlerAttribute"/>. /// </summary> /// <param name="sagaStore">The saga store to pass on to any <see cref="SagaEventHandler"/> instances.</param> /// <param name="typeLocator">The type locator use to retrieve all known classes marked with <see cref="EventHandlerAttribute"/>.</param> /// <param name="serviceProvider">The service locator used to retrieve singleton event handler dependencies.</param> /// <param name="commandPublisher">The command publisher used to publish saga commands.</param> private static Dictionary<Type, List<EventHandler>> DiscoverHandleMethods(ILocateTypes typeLocator, IServiceProvider serviceProvider, IStoreSagas sagaStore, Lazy<IPublishCommands> commandPublisher) { var handlerTypes = typeLocator.GetTypes(type => !type.IsAbstract && type.IsClass && type.GetCustomAttribute<EventHandlerAttribute>() != null); var knownEventHandlers = new Dictionary<Type, List<EventHandler>>(); foreach (var handlerType in handlerTypes) { var handleMethods = GetHandleMethods(handlerType, serviceProvider); var sagaMetadata = typeof(Saga).IsAssignableFrom(handlerType) ? GetSagaMetadata(handlerType, handleMethods) : null; foreach (var handleMethod in handleMethods) { List<EventHandler> eventHandlers; Type eventType = handleMethod.Key; if (!knownEventHandlers.TryGetValue(eventType, out eventHandlers)) knownEventHandlers.Add(eventType, eventHandlers = new List<EventHandler>()); var eventHandler = new EventHandler(handlerType, eventType, handleMethod.Value, GetHandlerFactory(handlerType, serviceProvider)); if (sagaMetadata != null) eventHandler = eventType == typeof(Timeout) ? new SagaTimeoutHandler(eventHandler, sagaMetadata, sagaStore, commandPublisher) : new SagaEventHandler(eventHandler, sagaMetadata, sagaStore, commandPublisher); eventHandlers.Add(eventHandler); } } return knownEventHandlers; }
/// <summary> /// Discover all event handlers associated with any locatable class marked with <see cref="EventHandlerAttribute"/>. /// </summary> /// <param name="sagaStore">The saga store to pass on to any <see cref="SagaEventHandler"/> instances.</param> /// <param name="typeLocator">The type locator use to retrieve all known classes marked with <see cref="EventHandlerAttribute"/>.</param> /// <param name="serviceProvider">The service locator used to retrieve singleton event handler dependencies.</param> /// <param name="commandPublisher">The command publisher used to publish saga commands.</param> private static Dictionary <Type, EventHandler[]> DiscoverEventHandlers(ILocateTypes typeLocator, IServiceProvider serviceProvider, IStoreSagas sagaStore, Lazy <IPublishCommands> commandPublisher) { var knownEvents = typeLocator.GetTypes(type => !type.IsAbstract && type.IsClass && type.DerivesFrom(typeof(Event))); var knownHandlers = DiscoverHandleMethods(typeLocator, serviceProvider, sagaStore, commandPublisher); var result = new Dictionary <Type, EventHandler[]>(); var logMessage = new StringBuilder(); logMessage.AppendLine("Discovered event handlers:"); foreach (var eventType in knownEvents.OrderBy(type => type.FullName)) { var eventHandlers = eventType.GetTypeHierarchy().Reverse() .Where(knownHandlers.ContainsKey) .SelectMany(type => knownHandlers[type]) .OrderBy(handler => handler is SagaEventHandler) .ThenBy(handler => handler.HandlerType.AssemblyQualifiedName) .ToArray(); logMessage.Append(" "); logMessage.Append(eventType); logMessage.AppendLine(); foreach (var eventHandler in eventHandlers) { logMessage.Append(" "); logMessage.Append(eventHandler.HandlerType); logMessage.AppendLine(); } result.Add(eventType, eventHandlers); } Log.Debug(logMessage.ToString); return(result); }
/// <summary> /// Initializes a new instance of <see cref="HookableSagaStore"/>. /// </summary> /// <param name="sagaStore">The underlying <see cref="IStoreSagas"/> implementation to be decorated.</param> /// <param name="pipelineHooks">The set of zero or more <see cref="PipelineHook"/> implementations used to extend <see cref="IStoreSagas"/> behavior.</param> public HookableSagaStore(IStoreSagas sagaStore, IEnumerable<PipelineHook> pipelineHooks) : this(sagaStore, pipelineHooks.EmptyIfNull().OrderBy(hook => hook.Order).ThenBy(hook => hook.GetType().FullName).ToList()) { }
/// <summary> /// Initializes a new instance of <see cref="SagaEventHandler"/>. /// </summary> /// <param name="eventHandler">The base event handler to decorate.</param> /// <param name="sagaMetadata">The saga metadata associated with this saga event handler.</param> /// <param name="sagaStore">The saga store used to load/save saga state.</param> /// <param name="commandPublisher">The command publisher used to publish saga commands.</param> internal SagaEventHandler(EventHandler eventHandler, SagaMetadata sagaMetadata, IStoreSagas sagaStore, Lazy <IPublishCommands> commandPublisher) : this(eventHandler, sagaMetadata, sagaStore, commandPublisher, Settings.SagaStore) { }
/// <summary> /// Initializes a new instance of <see cref="EventHandlerRegistry"/> with the specified <paramref name="typeLocator"/> and <paramref name="serviceProvider"/>. /// </summary> /// <param name="sagaStore">The saga store to pass on to any <see cref="SagaEventHandler"/> instances.</param> /// <param name="typeLocator">The type locator used to retrieve all known <see cref="Event"/> types.</param> /// <param name="serviceProvider">The service locator used to retrieve singleton event handler dependencies.</param> /// <param name="commandPublisher">The command publisher used to publish saga commands.</param> public EventHandlerRegistry(ILocateTypes typeLocator, IServiceProvider serviceProvider, IStoreSagas sagaStore, Lazy <IPublishCommands> commandPublisher) { Verify.NotNull(sagaStore, nameof(sagaStore)); Verify.NotNull(typeLocator, nameof(typeLocator)); Verify.NotNull(serviceProvider, nameof(serviceProvider)); Verify.NotNull(commandPublisher, nameof(commandPublisher)); knownEventHandlers = DiscoverEventHandlers(typeLocator, serviceProvider, sagaStore, commandPublisher); knownSagaTimeoutHandlers = knownEventHandlers.Where(item => typeof(Timeout).IsAssignableFrom(item.Key)) .SelectMany(item => item.Value) .OfType <SagaEventHandler>() .Distinct(item => item.HandlerType) .ToDictionary(item => item.HandlerType, item => new EventHandler[] { item }); }
/// <summary> /// Initializes a new instance of <see cref="HookableSagaStore"/>. /// </summary> /// <param name="sagaStore">The underlying <see cref="IStoreSagas"/> implementation to be decorated.</param> /// <param name="pipelineHooks">The set of zero or more <see cref="PipelineHook"/> implementations used to extend <see cref="IStoreSagas"/> behavior.</param> public HookableSagaStore(IStoreSagas sagaStore, IEnumerable <PipelineHook> pipelineHooks) : this(sagaStore, pipelineHooks.EmptyIfNull().OrderBy(hook => hook.Order).ThenBy(hook => hook.GetType().FullName).ToList()) { }