override public RuleResult Run()

in Source/Rules/CallFrequencyRule.cs [42:122]


        override public RuleResult Run(IEnumerable<ServiceCallItem> items, ServiceCallStats stats)
        {
            RuleResult result = InitializeResult(DisplayName, Description);

            m_stats = stats;
            m_endpointSustainedViolations = 0;
            m_endpointBurstViolations = 0;

            // For set of limits, look through items to determine where excess calls occurred
            foreach (var limits in m_rateLimits)
            {
                // Filter the full list of service calls to those which apply to this set of limits
                List<ServiceCallItem> applicableCalls = items.Where(serviceCall => 
                {
                    foreach (var subpath in limits.m_applicableSubpaths)
                    {
                        var subpathRegex = new Regex("^" + Regex.Escape(subpath).Replace("\\?", ".").Replace("\\*", ".*") + "$");
                        if (subpathRegex.IsMatch(new Uri(serviceCall.m_uri).AbsolutePath))
                        {
                            return true;
                        }
                    }
                    return false;
                }).ToList();

                var sustainedExcessCallsPerWindow = Utils.GetExcessCallsForTimeWindow(applicableCalls, limits.m_sustainedTimePeriodSeconds * 1000, limits.m_sustainedCallLimit);
                var burstExcessCallsPerWindow = Utils.GetExcessCallsForTimeWindow(applicableCalls, limits.m_burstTimePeriodSeconds * 1000, limits.m_burstCallLimit);

                foreach (var excessCalls in sustainedExcessCallsPerWindow)
                {
                    if (excessCalls.Count >= limits.m_sustainedCallLimit * 10)
                    {
                        var desc = $"Exceeding rate limits for '{limits.m_description}' required for title certification( limit of {limits.m_sustainedCallLimit * 10} calls with {excessCalls.Count} calls in {limits.m_sustainedTimePeriodSeconds} seconds).  Failure to adhere to the specified limits may block a title from release, and in-production issues with released titles may result in service suspension up to and including title removal.";
                        result.AddViolation(ViolationLevel.Error, desc, excessCalls);
                    }
                    else
                    {
                        var desc = $"Call frequency above the sustained call limit for '{limits.m_description}' (limit of {limits.m_sustainedCallLimit} exceeded with {excessCalls.Count} calls in {limits.m_sustainedTimePeriodSeconds} seconds).";
                        result.AddViolation(ViolationLevel.Warning, desc, excessCalls);
                    }
                    m_endpointSustainedViolations++;
                }

                foreach (var excessCalls in burstExcessCallsPerWindow)
                {
                    var desc = $"Call frequency above the burst call limit for '{limits.m_description}' (limit of {limits.m_burstCallLimit} exceeded with {excessCalls.Count} calls in {limits.m_burstTimePeriodSeconds} seconds).";
                    result.AddViolation(ViolationLevel.Warning, desc, excessCalls);
                    m_endpointBurstViolations++;
                }

                // The following is information that would only be useful for internal purposes. 
                if (RulesEngine.m_isInternal)
                {
                    UInt64 avgTimeBetweenReqsMs = stats.m_avgTimeBetweenReqsMs;
                    UInt64 avgElapsedCallTimeMs = stats.m_avgElapsedCallTimeMs;
                    UInt64 maxElapsedCallTimeMs = stats.m_maxElapsedCallTimeMs;


                    if (avgTimeBetweenReqsMs > 0 && avgTimeBetweenReqsMs < limits.m_avgTimeBetweenReqsMs)
                    {
                        result.AddViolation(ViolationLevel.Warning, "Average time of " + avgTimeBetweenReqsMs + "ms between calls is too short");
                    }

                    if (avgElapsedCallTimeMs > 0 && avgElapsedCallTimeMs > limits.m_avgElapsedCallTimeMs)
                    {
                        result.AddViolation(ViolationLevel.Warning, "Calls are taking longer than expected to return " + avgElapsedCallTimeMs + "ms");
                    }

                    if (maxElapsedCallTimeMs > 0 && maxElapsedCallTimeMs > limits.m_maxElapsedCallTimeMs)
                    {
                        result.AddViolation(ViolationLevel.Warning, "The maximum call time for calls is greater than allowed " + maxElapsedCallTimeMs + "ms");
                    }
                }
            }

            result.Results.Add("Total Calls", m_stats == null ? 0 : m_stats.m_numCalls);
            result.Results.Add("Times Sustained Exceeded", m_endpointSustainedViolations);
            result.Results.Add("Times Burst Exceeded", m_endpointBurstViolations);

            return result;
        }