public virtual async ValueTask <MessageReadResult <T> > ReadAsync() { DateTime timeReceived = DateTime.UtcNow; bool partialMessage = false; // Try to read one full message. try { T message = default; SequencePosition read = default; var closeToken = closeCts?.Token ?? default; ReadResult result = await duplexMessageStream.ReadAsync(closeToken).ConfigureAwait(false); var buffer = result.Buffer; while (!Deserializer.Deserialize(in buffer, out read, out message)) { // This case means we read a partial message, so try to read the rest if (!result.IsCompleted) { duplexMessageStream.AdvanceReaderTo(read, result.Buffer.End); ReadStats.IncrBytesRead(result.Buffer.Length); result = await duplexMessageStream.ReadAsync(closeToken).ConfigureAwait(false); buffer = result.Buffer; } // We didn't have enough data in the buffer, and the reader is closed so we can't read anymore, so mark it as a partial message. else { partialMessage = true; break; } } // Track the time it took to parse DateTime parsedTimeUtc = DateTime.UtcNow; if (!partialMessage) { // not sure how expensive this is var slicedBuffer = result.Buffer.Slice(result.Buffer.Start, read); ReadStats.IncMessagesRead(); ReadStats.IncrBytesRead(slicedBuffer.Length); try { ReadStats.IncMessagesIncomingBufferProcessing(1); await ProcessIncomingBufferAsync(message, slicedBuffer).ConfigureAwait(false); ReadStats.DecMessagesIncomingBufferProcessing(1); } catch (Exception ex) { ReadStats.DecMessagesIncomingBufferProcessing(1); Logger?.LogError(ex, "Error processing incoming message buffer."); } } if (!partialMessage) { duplexMessageStream.AdvanceReaderTo(read); } DateTime parsedTime = DateTime.UtcNow; return(new MessageReadResult <T> { // if the stream is completed, we can still try to read more messages, so we use the partialMessage field to indicate that. IsCompleted = result.IsCompleted && partialMessage, Error = false, Exception = null, Result = message, ReadResult = !partialMessage, ReceivedTimeUtc = timeReceived, ParsedTimeUtc = parsedTimeUtc }); } catch (Exception ex) { Logger?.LogError(ex, "Error reading message from duplex message stream."); return(new MessageReadResult <T> { IsCompleted = duplexMessageStream.ReadCompleted, Error = true, Exception = ex, Result = default,