public override async Task OpenAsync(CancellationToken cancellationToken = default)
        {
            if (Open)
            {
                throw new MessageStreamOpenException("MessageStream already open");
            }

            requests.Clear();
            closeCounter = 0;
            closing      = false;
            ReadChannelStats.Reset();
            WriteChannelStats.Reset();

            // Open the underlying stream first
            try
            {
                await base.OpenAsync(cancellationToken).ConfigureAwait(false);
            }
            catch (Exception)
            {
                Cleanup();
                throw;
            }

            // Creates our read/write channels
            Channel <TInner> GetChannel <TInner>(ChannelOptions options)
            {
                if (options is UnboundedChannelOptions)
                {
                    return(Channel.CreateUnbounded <TInner>((UnboundedChannelOptions)options));
                }
                else
                {
                    return(Channel.CreateBounded <TInner>((BoundedChannelOptions)options));
                }
            }

            readChannel  = GetChannel <MessageReadResult <T> >(concurrentOptions.ReaderChannelOptions);
            writeChannel = GetChannel <MessageWriteRequest>(concurrentOptions.WriterChannelOptions);

            readChannelTask  = concurrentOptions.ChannelTaskFactory.StartNew(ReadLoopAsync, concurrentOptions.ReadChannelTaskOptions).Unwrap();
            writeChannelTask = concurrentOptions.ChannelTaskFactory.StartNew(WriteLoopAsync, concurrentOptions.WriteChannelTaskOptions).Unwrap();

            if (readChannelTask.IsCompleted && !readChannelTask.IsCompletedSuccessfully)
            {
                await CleanupOpenAsync().ConfigureAwait(false);

                throw readChannelTask.Exception;
            }

            if (writeChannelTask.IsCompleted && !writeChannelTask.IsCompletedSuccessfully)
            {
                await CleanupOpenAsync().ConfigureAwait(false);

                throw writeChannelTask.Exception;
            }

            readChannelCleanupTask  = readChannel.Reader.Completion.ContinueWith((result) => ReadChannelCompleteAsync(result), TaskContinuationOptions.RunContinuationsAsynchronously);
            writeChannelCleanupTask = writeChannel.Reader.Completion.ContinueWith((result) => WriteChannelCompleteAsync(result), TaskContinuationOptions.RunContinuationsAsynchronously);
        }
        private void Cleanup()
        {
            // Stop channels
            CompleteChannels();

            // Reset stats
            ReadChannelStats.Reset();
            WriteChannelStats.Reset();

            // Complete any left over requests.
            foreach (var request in requests.Values)
            {
                request.resultTcs.TrySetResult(new MessageReadResult <T>
                {
                    Error       = true,
                    Exception   = new TaskCanceledException("Request timed out"),
                    IsCompleted = true,
                    Result      = default,