/// <summary>
        ///     Runs the receive / reconnect life cycle asynchronously.
        /// </summary>
        /// <returns>a task that represents the asynchronous operation</returns>
        /// <exception cref="ObjectDisposedException">thrown if the instance is disposed</exception>
        private async Task RunLifeCycleAsync()
        {
            EnsureNotDisposed();

            while (!_cancellationTokenSource !.IsCancellationRequested)
            {
                // receive new payload until the web-socket is connected.
                while (IsConnected && !_cancellationTokenSource.IsCancellationRequested)
                {
                    await ProcessNextPayload();
                }

                var lostConnectionAt = DateTimeOffset.UtcNow;

                // try reconnect
                for (var attempt = 1; !_cancellationTokenSource.IsCancellationRequested; attempt++)
                {
                    // reconnect
                    await ConnectAsync();

                    if (IsConnected)
                    {
                        // reconnection successful
                        break;
                    }

                    var eventArgs = new ReconnectAttemptEventArgs(_webSocketUri, attempt, _reconnectionStrategy);
                    await OnReconnectAttemptAsync(eventArgs);

                    // give up
                    if (eventArgs.CancelReconnect)
                    {
                        Logger?.Log(this, "Reconnection aborted due event.");
                        return;
                    }

                    // add delay between reconnects
                    var delay = _reconnectionStrategy(lostConnectionAt, attempt);

                    // reconnection give up
                    if (delay is null)
                    {
                        Logger?.Log(this, "Reconnection failed! .. giving up.", LogLevel.Warning);
                        return;
                    }

                    Logger?.Log(this, string.Format("Waiting {0} before next reconnect attempt...", delay.Value), LogLevel.Debug);
                    await Task.Delay(delay.Value);
                }
            }
        }
 /// <summary>
 ///     Triggers the <see cref="ReconnectAttempt"/> event asynchronously.
 /// </summary>
 /// <param name="eventArgs">the event arguments</param>
 /// <returns>a task that represents the asynchronously operation.</returns>
 protected virtual Task OnReconnectAttemptAsync(ReconnectAttemptEventArgs eventArgs)
 => ReconnectAttempt.InvokeAsync(this, eventArgs);