private void KeySpaceNotificationHandler(string target, string operation)
        {
            if (key != target)
            {
                return;
            }
            switch (operation)
            {
            case "expired":
            {
                Task.Run(() => Transition(
                             null,
                             JsonConvert.SerializeObject(
                                 new CircuitBreakerStateDescriptor(CircuitBreakerState.HalfOpen, Clock.Current.Now()),
                                 JsonSerializationSettings), true));
            }
            break;

            default:
                ReadDescriptor().ContinueWith(task =>
                {
                    var desc            = task.Result;
                    stateDescriptor     = desc;
                    lastSerializedState = JsonConvert.SerializeObject(stateDescriptor, JsonSerializationSettings);
                    foreach (var observer in subscribers)
                    {
                        observer(desc);
                    }
                });
                break;
            }
        }
        private async Task TransitionStateTo(CircuitBreakerStateDescriptor targetState, TimeSpan?expiry = null)
        {
            var shoudLogEvent = IsNullOrWhiteSpace(lastSerializedState) || targetState.State == CircuitBreakerState.Open || stateDescriptor?.State != targetState.State;
            var serialized    = JsonConvert.SerializeObject(targetState, JsonSerializationSettings);
            var stateExpiry   = targetState.State == CircuitBreakerState.Open && expiry == null
                ? TimeSpan.FromMinutes(1)
                : expiry;

            await Transition(lastSerializedState, serialized, shoudLogEvent, stateExpiry);
        }
        public async Task SignalSuccessAsync()
        {
            var target = CircuitBreakerState.Closed;

            if (stateDescriptor?.State == CircuitBreakerState.Open)
            {
                target = CircuitBreakerState.HalfOpen;
            }
            var targetState = new CircuitBreakerStateDescriptor(target, Clock.Current.Now());

            await TransitionStateTo(targetState);
        }
        private async Task <CircuitBreakerStateDescriptor> ReadDescriptor()
        {
            var desc = new CircuitBreakerStateDescriptor(CircuitBreakerState.Closed, Clock.Now());
            var src  = await db.StringGetAsync(key);

            if (!src.IsNullOrEmpty && !IsNullOrWhiteSpace(src))
            {
                desc = JsonConvert.DeserializeObject <CircuitBreakerStateDescriptor>(src, JsonSerializationSettings);
            }

            return(desc);
        }
        public async Task <CircuitBreakerStateDescriptor> GetLastStateAsync()
        {
            var serialised = await db.StringGetAsync(key);

            lastSerializedState = serialised.HasValue ? serialised.ToString() : Empty;

            if (IsNullOrWhiteSpace(serialised))
            {
                var newState = new CircuitBreakerStateDescriptor(CircuitBreakerState.Closed, Clock.Current.Now(),
                                                                 TimeSpan.FromMinutes(1));
                lastSerializedState = await Transition(lastSerializedState,
                                                       JsonConvert.SerializeObject(newState, JsonSerializationSettings), true);
            }

            return(TryDeserialise(lastSerializedState));
        }
        public async Task SignalFailureAsync(TimeSpan expiry)
        {
            var openState = new CircuitBreakerStateDescriptor(CircuitBreakerState.Open, Clock.Current.Now(), expiry);

            await TransitionStateTo(openState, expiry);
        }