public virtual async Task Shutdown()
        {
            await connectLock.WaitAsync();

            try
            {
                if (!running)
                {
                    return;
                }

                this.running = false;
                lock (stateLock)
                {
                    Monitor.PulseAll(stateLock);
                }

                if (State != ConnectionState.Closed)
                {
                    this.State = ConnectionState.Closing;
                    this.eventArgsSubject.Publish(ConnectionEventArgs.ClosingEventArgs);
                    await DoDisconnect();

                    this.State = ConnectionState.Closed;
                    this.eventArgsSubject.Publish(ConnectionEventArgs.ClosedEventArgs);
                }

                if (idleStateMonitor != null)
                {
                    idleStateMonitor.IdleStateChanged -= OnIdleStateChanged;
                    idleStateMonitor.Dispose();
                }

                foreach (var kv in promises)
                {
                    var promise = kv.Value;
                    promise.SetCanceled();
                }
                this.promises.Clear();
            }
            catch (Exception) { }
            finally
            {
                connectLock.Release();
            }
        }
        public virtual async Task Shutdown()
        {
            await connectLock.WaitAsync().ConfigureAwait(false);

            try
            {
                if (shutdownTokenSource == null)
                {
                    return;
                }

                this.shutdownTokenSource.Cancel();
                this.shutdownTokenSource = null;

                if (State != ConnectionState.Closed)
                {
                    this.State = ConnectionState.Closing;
                    this.eventArgsSubject.Publish(ConnectionEventArgs.ClosingEventArgs);
                    await DoDisconnect().ConfigureAwait(false);

                    this.State = ConnectionState.Closed;
                    this.eventArgsSubject.Publish(ConnectionEventArgs.ClosedEventArgs);
                }

                if (idleStateMonitor != null)
                {
                    idleStateMonitor.IdleStateChanged -= OnIdleStateChanged;
                    idleStateMonitor.Dispose();
                }

                foreach (var kv in promises)
                {
                    var promise = kv.Value;
                    promise.SetCanceled();
                }
                this.promises.Clear();
            }
            catch (Exception) { }
            finally
            {
                connectLock.Release();
            }
        }