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;
}