コード例 #1
0
ファイル: Replicator.cs プロジェクト: EventStore/replicator
        public static async Task Replicate(
            IEventReader reader,
            SinkPipeOptions sinkPipeOptions,
            PreparePipelineOptions preparePipeOptions,
            ICheckpointStore checkpointStore,
            CancellationToken stoppingToken,
            bool restartWhenComplete = false
            )
        {
            ReplicationMetrics.SetCapacity(preparePipeOptions.BufferSize, sinkPipeOptions.BufferSize);

            var cts = new CancellationTokenSource();

            var linkedCts =
                CancellationTokenSource.CreateLinkedTokenSource(stoppingToken, cts.Token);

            var prepareChannel = Channel.CreateBounded <PrepareContext>(preparePipeOptions.BufferSize);
            var sinkChannel    = Channel.CreateBounded <SinkContext>(sinkPipeOptions.BufferSize);

            var readerPipe = new ReaderPipe(
                reader,
                checkpointStore,
                ctx => prepareChannel.Writer.WriteAsync(ctx, ctx.CancellationToken)
                );

            var preparePipe = new PreparePipe(
                preparePipeOptions.Filter,
                preparePipeOptions.Transform,
                ctx => sinkChannel.Writer.WriteAsync(ctx, ctx.CancellationToken)
                );
            var sinkPipe = new SinkPipe(sinkPipeOptions, checkpointStore);

            var prepareTask = CreateChannelShovel(
                "Prepare",
                prepareChannel,
                preparePipe.Send,
                ReplicationMetrics.PrepareChannelSize,
                linkedCts.Token
                );

            var writerTask = CreateChannelShovel(
                "Writer",
                sinkChannel,
                sinkPipe.Send,
                ReplicationMetrics.SinkChannelSize,
                CancellationToken.None
                );
            var reporter = Task.Run(Report, stoppingToken);

            while (true)
            {
                ReplicationStatus.Start();

                await readerPipe.Start(linkedCts.Token).ConfigureAwait(false);

                if (!restartWhenComplete)
                {
                    do
                    {
                        Log.Info("Closing the prepare channel...");
                        await Task.Delay(1000, CancellationToken.None).ConfigureAwait(false);
                    } while (!prepareChannel.Writer.TryComplete());
                }

                ReplicationStatus.Stop();

                while (sinkChannel.Reader.Count > 0)
                {
                    await checkpointStore.Flush(CancellationToken.None).ConfigureAwait(false);

                    Log.Info("Waiting for the sink pipe to exhaust ({Left} left)...", sinkChannel.Reader.Count);
                    await Task.Delay(1000, CancellationToken.None).ConfigureAwait(false);
                }

                Log.Info("Storing the last known checkpoint");
                await checkpointStore.Flush(CancellationToken.None).ConfigureAwait(false);

                if (linkedCts.IsCancellationRequested || !restartWhenComplete)
                {
                    sinkChannel.Writer.Complete();
                    break;
                }

                Log.Info("Will restart in 5 sec");
                await Task.Delay(5000, stoppingToken);
            }

            try {
                await prepareTask.ConfigureAwait(false);

                await writerTask.ConfigureAwait(false);

                await reporter.ConfigureAwait(false);
            }
            catch (OperationCanceledException) { }