//-----------------------------------------------------------------------------
//
// Copyright 2016 Amazon.com, Inc. or its affiliates. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License").
// You may not use this file except in compliance with the License.
// A copy of the License is located at
//
// http://aws.amazon.com/apache2.0
//
// or in the "license" file accompanying this file. This file is distributed
// on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
// express or implied. See the License for the specific language governing
// permissions and limitations under the License.
//
//-----------------------------------------------------------------------------
using Amazon.Runtime.Internal.Util;
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
namespace Amazon.XRay.Recorder.Core.Sampling
{
///
/// The poller to report the current statistics of all
/// sampling rules and retrieve the new allocated
/// sampling quota and TTL from X-Ray service.
///
public class TargetPoller
{
private static readonly Logger _logger = Logger.GetLogger(typeof(TargetPoller));
private RuleCache _ruleCache;
private RulePoller _rulePoller;
private IConnector _connector;
private const int RefreshInterval = 10 * 1000; // 10 seconds
private const double MaxJitter = 0.1 * 1000; // adding max jitter upto 0.1 seconds
private readonly Random _random = new Random();
private Timer _timer;
public TargetPoller(RuleCache ruleCache, RulePoller rulePoller)
{
_ruleCache = ruleCache;
_rulePoller = rulePoller;
}
internal void Poll(IConnector connector)
{
_connector = connector;
_timer = InitializeTimer();
}
private Timer InitializeTimer()
{
return new Timer(Start, null, GetDelay(), 0); // First execution after GetDelay() time
}
internal async void Start(Object state)
{
try
{
await RefreshTargets();
}
catch (Exception e)
{
_logger.Error(e, "Encountered exception while polling targets");
}
finally
{
_timer.Change(GetDelay(), 0);
}
}
internal async Task RefreshTargets()
{
List rules = GetCandidates();
if(rules == null || rules.Count == 0)
{
_logger.DebugFormat("There is no sampling rule statistics to report, skipping.");
return;
}
_logger.DebugFormat("Reporting rule statistics to get new quota.");
GetSamplingTargetsResponse response = await _connector.GetSamplingTargets(rules);
_ruleCache.LoadTargets(response.Targets);
if (response.RuleFreshness.IsGreaterThan(_ruleCache.LastUpdated))
{
_logger.InfoFormat("Performing out-of-band sampling rule polling to fetch updated rules.");
_rulePoller.WakeUp();
}
}
///
/// Don't report a rule statistics if any of the conditions is met:
/// 1. The report time hasn't come (some rules might have larger report intervals).
/// 2. The rule is never matched.
///
/// List of .
private List GetCandidates()
{
List candidates = new List();
IList rules = _ruleCache.GetRules();
TimeStamp now = TimeStamp.CurrentTime();
foreach (var rule in rules)
{
if (rule.ShouldReport(now))
{
candidates.Add(rule);
}
}
return candidates;
}
private int GetDelay()
{
return RefreshInterval + GenerateRandomJitter();
}
private int GenerateRandomJitter()
{
return _random.Next(1, (int) MaxJitter);
}
}
}