/// <inheritdoc />
        public void SubscribeToChannels(TimeSpan timeout, IEnumerable <string> channelsToSubscribe)
        {
            if (channelsToSubscribe == null)
            {
                throw new ArgumentNullException("channelsToSubscribe");
            }

            Trace.WriteLine("ENTER: Subscribing to channels {0} ...".FormatInvariant(channelsToSubscribe.ToString(",")));

            if (timeout <= TimeSpan.Zero)
            {
                throw new ArgumentOutOfRangeException("timeout", timeout, "Value must be positive.");
            }

            if (this.disposeState != DisposeState.None)
            {
                throw new ObjectDisposedException(this.debugName);
            }

            List <string> channelsToSubscribe1 = channelsToSubscribe
                                                 .Except(this.channels)
                                                 .Distinct()
                                                 .ToList();

            if (channelsToSubscribe1.Count == 0)
            {
                Trace.WriteLine("EXIT: No channels to subscribe.");

                return;
            }

            if (this.channels.Count == 0)
            {
                channelsToSubscribe1.Add(ServiceStackSubscription.UnsubscribeChannel);
            }

            SubscribeOperationState subscribeOperation = new SubscribeOperationState(SubscribeOperation.Subscribe, channelsToSubscribe1);

            this.subscribeOperations.Add(subscribeOperation);

            ThreadPool.QueueUserWorkItem(state =>
            {
                try
                {
                    this.subscription.SubscribeToChannels(channelsToSubscribe1.ToArray());
                }
                catch (Exception ex)
                {
                    if (ex.IsCritical())
                    {
                        throw;
                    }

                    Trace.TraceWarning(ex.ToString());
                }
            });

            if (timeout == TimeSpan.MaxValue)
            {
                subscribeOperation.Blocker.Wait();
            }
            else if (!subscribeOperation.Blocker.Wait(timeout))
            {
                throw new TimeoutException("Subscribe to channels '{0}' timed out after {1}.".FormatInvariant(channelsToSubscribe.ToString(","), timeout));
            }

            Trace.WriteLine("EXIT: Subscribed to channels {0}.".FormatInvariant(channelsToSubscribe.ToString(",")));
        }
        /// <inheritdoc />
        public bool UnsubscribeFromChannels(TimeSpan timeout, IEnumerable <string> channelsToUnsubscribe)
        {
            if (channelsToUnsubscribe == null)
            {
                throw new ArgumentNullException("channelsToUnsubscribe");
            }

            string channelsDebugString = channelsToUnsubscribe.ToString(",");

            Trace.WriteLine("ENTER: Unsubscribing from channels {0} ...".FormatInvariant(channelsDebugString));

            if (timeout <= TimeSpan.Zero)
            {
                throw new ArgumentOutOfRangeException("timeout", timeout, "Value must be positive.");
            }

            if (this.disposeState != DisposeState.None)
            {
                Trace.Flush();

                throw new ObjectDisposedException(this.debugName);
            }

            List <string> channelsToUnsubscribe1 = channelsToUnsubscribe.Where(c => this.channels.Contains(c)).Distinct().ToList();

            if (channelsToUnsubscribe1.Count == 0)
            {
                Trace.WriteLine("EXIT: No channels to unsubscribe from.");

                return(true);
            }

            if (channelsToUnsubscribe1.Count == this.channels.Count)
            {
                channelsToUnsubscribe1.Add(UnsubscribeChannel);
            }

            SubscribeOperationState subscribeOperation = new SubscribeOperationState(SubscribeOperation.Unsubscribe, channelsToUnsubscribe);

            this.subscribeOperations.Add(subscribeOperation);

            using (RedisClient client2 = new RedisClient(this.client.Host))
            {
                client2.PublishMessage(ServiceStackSubscription.UnsubscribeChannel, RedisConverter.ToString(channelsToUnsubscribe));
            }

            if (timeout == TimeSpan.MaxValue)
            {
                subscribeOperation.Blocker.Wait();

                Trace.WriteLine("EXIT: Unsubscribed from channels {0}.".FormatInvariant(channelsDebugString));

                return(true);
            }

            if (subscribeOperation.Blocker.Wait(timeout))
            {
                Trace.WriteLine("EXIT: Unsubscribed from channels {0}.".FormatInvariant(channelsDebugString));

                return(true);
            }
            else
            {
                Trace.WriteLine("EXIT: Failed to unsubscribe from channels {0} within the specified timeout {1}.".FormatInvariant(channelsDebugString, timeout));

                return(false);
            }
        }