예제 #1
0
 public PoolingProjector(IPassiveEventStore eventStore, T projection, ILogger <T> logger)
 {
     _eventStore   = eventStore;
     _projection   = projection;
     _logger       = logger;
     EventPageSize = 10;
     PoolingTimer  = TimeSpan.FromSeconds(2);
 }
            When_a_subscription_starts_after_zero_checkpoint_and_another_subscription_starts_after_null_checkpoint_while_the_first_subscription_is_loading_the_first_page_from_the_event_store()
            {
                Given(() =>
                {
                    IPassiveEventStore eventStore = A.Fake <IPassiveEventStore>();
                    A.CallTo(() => eventStore.GetFrom(A <long?> .Ignored)).ReturnsLazily(call =>
                    {
                        long checkpoint = call.GetArgument <long?>(0) ?? 0;

                        aSubscriptionStartedLoading.Set();

                        if (!secondSubscriptionCreated.Wait(TimeSpan.FromSeconds(10)))
                        {
                            throw new InvalidOperationException("The second subscription has not been created in 10 seconds.");
                        }

                        // Give the second subscription enough time to access the cache.
                        Thread.Sleep(TimeSpan.FromSeconds(1));

                        return(checkpoint > 0
                            ? new Transaction[0]
                            : new[] { new TransactionBuilder().WithCheckpoint(1).Build() });
                    });

                    var adapter = new PollingEventStoreAdapter(eventStore, 11, pollingInterval, 100, () => DateTime.UtcNow);
                    WithSubject(_ => adapter.Subscribe);
                });

                When(() =>
                {
                    Subject(0, new Subscriber
                    {
                        HandleTransactions = (transactions, info) => Task.FromResult(0)
                    }, "firstId");

                    if (!aSubscriptionStartedLoading.Wait(TimeSpan.FromSeconds(10)))
                    {
                        throw new InvalidOperationException("The first subscription has not started loading in 10 seconds.");
                    }

                    Subject(null, new Subscriber
                    {
                        HandleTransactions = (transactions, info) =>
                        {
                            secondSubscriptionReceivedTheTransaction.Set();
                            return(Task.FromResult(0));
                        }
                    }, "secondId");

                    secondSubscriptionCreated.Set();
                });
            }
예제 #3
0
        /// <summary>
        /// Creates an adapter that observes an implementation of <see cref="IPassiveEventStore"/> and efficiently handles
        /// multiple subscribers.
        /// </summary>
        /// <param name="eventStore">
        /// The persistency implementation that the NEventStore is configured with.
        /// </param>
        /// <param name="cacheSize">
        /// The size of the LRU cache that will hold transactions already loaded from the event store. The larger the cache,
        /// the higher the chance multiple subscribers can reuse the same transactions without hitting the underlying event store.
        /// Set to <c>0</c> to disable the cache alltogether.
        /// </param>
        /// <param name="pollInterval">
        /// The amount of time to wait before polling again after the event store has not yielded any transactions anymore.
        /// </param>
        /// <param name="maxPageSize">
        /// The size of the page of transactions the adapter should load from the event store for every query.
        /// </param>
        /// <param name="getUtcNow">
        /// Provides the current date and time in UTC.
        /// </param>
        public PollingEventStoreAdapter(IPassiveEventStore eventStore, int cacheSize, TimeSpan pollInterval, int maxPageSize,
                                        Func <DateTime> getUtcNow)
        {
            this.eventStore   = eventStore;
            this.pollInterval = pollInterval;
            this.maxPageSize  = maxPageSize;
            this.getUtcNow    = getUtcNow;

            if (cacheSize > 0)
            {
                transactionCacheByPreviousCheckpoint = new LruCache <long, Transaction>(cacheSize);
            }
        }
예제 #4
0
        /// <summary>
        /// Creates an adapter that observes an implementation of <see cref="IPassiveEventStore"/> and efficiently handles
        /// multiple subscribers.
        /// </summary>
        /// <param name="eventStore">
        /// The persistency implementation that the NEventStore is configured with.
        /// </param>
        /// <param name="cacheSize">
        /// The size of the LRU cache that will hold transactions already loaded from the event store. The larger the cache,
        /// the higher the chance multiple subscribers can reuse the same transactions without hitting the underlying event store.
        /// Set to <c>0</c> to disable the cache alltogether.
        /// </param>
        /// <param name="pollInterval">
        /// The amount of time to wait before polling again after the event store has not yielded any transactions anymore.
        /// </param>
        /// <param name="maxPageSize">
        /// The size of the page of transactions the adapter should load from the event store for every query.
        /// </param>
        /// <param name="getUtcNow">
        /// Obsolete. Only kept in there to prevent breaking changes.
        /// </param>
        /// <param name="logger">
        /// An optional method for logging internal diagnostic messages as well as any exceptions that happen.
        /// </param>
        /// <remarks>
        /// Diagnostic information is only logged if this code is compiled with the LIQUIDPROJECTIONS_DIAGNOSTICS compiler symbol.
        /// </remarks>
        public PollingEventStoreAdapter(IPassiveEventStore eventStore, int cacheSize, TimeSpan pollInterval, int maxPageSize,
                                        Func <DateTime> getUtcNow, LogMessage logger = null)
        {
            this.eventStore   = eventStore;
            this.pollInterval = pollInterval;
            this.maxPageSize  = maxPageSize;

#if LIQUIDPROJECTIONS_DIAGNOSTICS
            this.logDebug = logger ?? (_ =>
            {
            });
#else
            this.logDebug = _ => {};
#endif
            this.logError = logger ?? (_ =>
            {
            });

            if (cacheSize > 0)
            {
                cachedTransactionsByPrecedingCheckpoint = new LruCache <long, Transaction>(cacheSize);
            }
        }