コード例 #1
0
        /// <summary>
        ///     Migrate events from the source stream to this migration stream.
        /// </summary>
        /// <param name="source">
        ///     Events are read from this stream.
        /// </param>
        /// <param name="migrator">
        ///     Function invoked to migrate an event. Receives the event and
        ///     its sequence number as argument, must return the event to be
        ///     written (or null if the event should be dropped).
        ///
        ///     The function will be invoked starting with the very first
        ///     event in the source stream, but its return value will be
        ///     ignored if the sequence number is smaller than the value
        ///     returned by <see cref="LastWrittenAsync"/> (the purpose of
        ///     this is to let the migrator function accumulate any necessary
        ///     internal state).
        ///
        ///     The events retain their sequence number. Dropped events (those
        ///     for which the migrator returns null) are not migrated at all.
        /// </param>
        /// <param name="refreshDelay">
        ///     No effect until migration has reached the end of the source
        ///     stream.
        ///
        ///     If null, migration ends when the end of the source stream is
        ///     reached.
        ///
        ///     If provided, once the end of the source stream is
        ///     reached, will poll the source stream forever (with this delay)
        ///     looking for new events.
        /// </param>
        /// <param name="cancel">
        ///     Invoke to interrupt the migration.
        /// </param>
        public async Task MigrateFromAsync(
            IEventStream <TEvent> source,
            Func <TEvent, uint, TEvent> migrator,
            TimeSpan?refreshDelay,
            CancellationToken cancel)
        {
            var lastSeq = await LastWrittenAsync(cancel);

            var list = new List <KeyValuePair <uint, TEvent> >();

            while (true)
            {
                cancel.ThrowIfCancellationRequested();

                var fetch = source.BackgroundFetchAsync();

                while (source.TryGetNext() is TEvent next)
                {
                    var seq = source.Sequence;

                    if (!(migrator(next, seq) is TEvent migrated))
                    {
                        // Do not migrate this event.
                        continue;
                    }

                    if (seq <= lastSeq)
                    {
                        // Event already migrated previously
                        continue;
                    }

                    list.Add(new KeyValuePair <uint, TEvent>(seq, migrated));
                }

                if (list.Count > 0)
                {
                    await WriteAsync(list, cancel).ConfigureAwait(false);

                    list.Clear();
                }

                var more = await fetch.ConfigureAwait(false);

                if (more())
                {
                    continue;
                }

                // Reached the end of the stream.
                if (refreshDelay == null)
                {
                    return;
                }
                else
                {
                    await Task.Delay(refreshDelay.Value, cancel).ConfigureAwait(false);
                }
            }
        }
コード例 #2
0
        /// <summary>
        /// provides the caller with the next event in the stream. It may trigger at most one call to <see cref="FetchAsync"/>.
        /// You may use this to implement active (polling) wait for an event. What this method won't do is block until a new
        /// event has been published.
        /// </summary>
        public static async Task <TEvent> TryGetNextAsync <TEvent>(this IEventStream <TEvent> stream, CancellationToken cancel = default(CancellationToken))
            where TEvent : class
        {
            var next = stream.TryGetNext();

            if (next != null)
            {
                return(next);
            }

            if (await stream.FetchAsync(cancel))
            {
                return(stream.TryGetNext());
            }

            return(null);
        }