private async Task ReadPipeAsync() { Exception shutdownReason = null; Exception unexpectedError = null; try { await ProcessMessagesAsync(); } catch (Exception ex) when((ex is SocketException socketEx && IsConnectionAbortError(socketEx.SocketErrorCode)) || ex is ObjectDisposedException) { // This should always be ignored since Shutdown() must have already been called by Abort(). shutdownReason = ex; } catch (Exception ex) { shutdownReason = ex; unexpectedError = ex; _logger.LogTrace(unexpectedError); } finally { Shutdown(shutdownReason); // Complete the output after disposing the socket ReaderPipe.Complete(unexpectedError); // Cancel any pending flushes so that the input loop is un-paused ReceiverPipe.CancelPendingFlush(); } }
private async Task ProcessMessagesAsync() { while (true) { var result = await ReaderPipe.ReadAsync(); if (result.IsCanceled) { break; } var buffer = result.Buffer; var end = buffer.End; var isCompleted = result.IsCompleted; if (!buffer.IsEmpty) { //SequenceReader is not allowed in async methods :( foreach (var seg in buffer) { if (!seg.IsEmpty) { await _handlerMapper.HandleAsync(seg); } } } ReaderPipe.AdvanceTo(end); if (isCompleted) { break; } } }
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) { }