private async Task ProcessNextFrame()
        {
            Frame frame = await this.reader.ReadNext();

            if (frame is ResponseFrame responseFrame)
            {
                this.tracer.TraceEvent(TraceEventType.Verbose, 0, "Read ResponseFrame of type {0}", responseFrame.Type);

                if (responseFrame.Type == ResponseType.Heartbeat)
                {
                    await WriteProtocolCommand(new NopCommand())
                    .ConfigureAwait(false);
                }
                else if (responseFrame.Type == ResponseType.Ok)
                {
                    // If publishing, unlock the Publish task that is awaiting
                    if (this.callbacksQueue.TryDequeue(out TaskCompletionSource <bool> tcs))
                    {
                        tcs.TrySetResult(true);
                    }
                }
            }
            else if (frame is MessageFrame messageFrame)
            {
                this.tracer.TraceEvent(TraceEventType.Verbose, 0, "Read MessageFrame with ID {0}", messageFrame.MessageId);

                await RaiseMessageEvent(messageFrame).ConfigureAwait(false);
            }
            else if (frame is ErrorFrame errorFrame)
            {
                // Note: we don't always get here, because the connection is closed by nsqd when errors happen
                // https://nsq.io/clients/building_client_libraries.html#a-brief-interlude-on-errors

                this.tracer.TraceEvent(TraceEventType.Verbose, 0, "Read ErrorFrame with message {0}", errorFrame.Message);

                NsqException exception = new NsqException(errorFrame.Message);

                RaiseErrorEvent(exception);

                // If publishing, throw the exception
                if (this.callbacksQueue.TryDequeue(out TaskCompletionSource <bool> tcs))
                {
                    tcs.TrySetException(exception);
                }
            }
        }
 private void RaiseErrorEvent(NsqException exception)
 {
     this.OnError?.Invoke(this, new NsqErrorEventArgs(exception));
 }