private static Task <ExceptionTarget> GetOrAddStringCachedExecptionTargetAsync(string input, ExceptionTarget target = null)
        {
            ExceptionTarget exTarget = null;

            if (_stringExceptionCache.ContainsKey(input))
            {
                exTarget = _stringExceptionCache[input];
            }
            else if (target is null)
            {
                exTarget = new ExceptionTarget
                {
                    AllowConsecutiveFailure = true,
                    FailureCount            = 0,
                    FailureCountMax         = 5,
                    GuaranteeFailure        = false
                };

                _stringExceptionCache[input] = exTarget;
            }
            else
            {
                _stringExceptionCache[input] = exTarget = target;
            }

            return(Task.FromResult(exTarget));
        }
        public static async Task RollsTheDiceAsync(object input, ExceptionTarget target = null)
        {
            switch (input)
            {
            case int userInput: await HandleIntAsync(userInput, target); break;

            case long userInput: await HandleLongAsync(userInput, target); break;

            case string userInput: await HandleStringAsync(userInput, target); break;

            default: break;
            }
        }
        private static async Task HandleIntAsync(int input, ExceptionTarget target = null, bool allowContextualCleanup = false)
        {
            var exTarget = await GetOrAddIntCachedExecptionTargetAsync(input, target);

            if (exTarget.FailureCount < exTarget.FailureCountMax)
            {
                var throwException = false;

                // Can We Throw Exception?
                if (exTarget.GuaranteeFailure ||
                    exTarget.AllowConsecutiveFailure ||
                    (!exTarget.AllowConsecutiveFailure && !exTarget.LastIterationFailed))
                {
                    // Will We Throw Exception?
                    throwException = await ShouldWeThrowExceptionAsync(input);

                    if (throwException) // The Math Gods Say Yes!
                    {
                        exTarget.FailureCount++;
                        exTarget.LastIterationFailed = true;
                    }
                    else
                    {
                        exTarget.LastIterationFailed = false;
                    }
                }
                else
                {
                    exTarget.LastIterationFailed = false;
                }

                // Update Cache
                _intExceptionCache[input] = exTarget;

                if (throwException)
                {
                    await ThrowsRandomExceptionAsync();
                }
            }
            else if (allowContextualCleanup) // We are finished with this input! Allows it come back in!
            {
                _intExceptionCache.TryRemove(input, out ExceptionTarget outTarget);
            }
        }