/// <summary>
        /// Creates a task that completes <paramref name="delay"/> after <see cref="IMonotonicTimer.CurrentTime"/>.
        /// </summary>
        /// <param name="timer"><see cref="IMonotonicTimer"/> instance.</param>
        /// <param name="delay">How much time to delay for.</param>
        /// <param name="cancellation">Cancellation token.</param>
        /// <returns>A task which completes when the delay has elapsed.</returns>
        public static async Task Delay(this IMonotonicTimer timer, TimeSpan delay, CancellationToken cancellation)
        {
            if (timer == null)
            {
                throw new ArgumentNullException(nameof(timer));
            }

            await timer.DelayUntil(timer.CurrentTime + delay, cancellation);
        }
        /// <summary>
        /// Initializes a new instance of the <see cref="RecurrentActivityManager"/> class.
        /// </summary>
        /// <param name="operationLogger">The operation logger.</param>
        /// <param name="monotonicTimer">Instance of <see cref="IMonotonicTimer"/> to aid in testability of the class.</param>
        public RecurrentActivityManager(
            IOperationLogger <RecurrentActivityManager> operationLogger,
            IMonotonicTimer monotonicTimer)
        {
            Contracts.CheckValue(operationLogger, nameof(operationLogger));
            Contracts.CheckValue(monotonicTimer, nameof(monotonicTimer));

            _operationLogger = operationLogger;
            _monotonicTimer  = monotonicTimer;
        }
Exemple #3
0
        /// <summary>
        /// Initializes a new instance of the <see cref="BackendProberFactory"/> class.
        /// </summary>
        public BackendProberFactory(IMonotonicTimer timer, ILoggerFactory loggerFactory, IOperationLogger operationLogger, IHealthProbeHttpClientFactory httpClientFactory)
        {
            Contracts.CheckValue(timer, nameof(timer));
            Contracts.CheckValue(loggerFactory, nameof(loggerFactory));
            Contracts.CheckValue(operationLogger, nameof(operationLogger));
            Contracts.CheckValue(httpClientFactory, nameof(httpClientFactory));

            _timer             = timer;
            _loggerFactory     = loggerFactory;
            _httpClientFactory = httpClientFactory;
            _randomFactory     = new RandomFactory();
            _operationLogger   = operationLogger;
        }
 /// <summary>
 /// Initializes a new instance of the <see cref="ClusterProberFactory"/> class.
 /// </summary>
 public ClusterProberFactory(
     IMonotonicTimer timer,
     ILogger <ClusterProber> logger,
     IOperationLogger <ClusterProber> operationLogger,
     IHealthProbeHttpClientFactory httpClientFactory,
     IRandomFactory randomFactory)
 {
     _timer             = timer ?? throw new ArgumentNullException(nameof(timer));
     _logger            = logger ?? throw new ArgumentNullException(nameof(logger));
     _httpClientFactory = httpClientFactory ?? throw new ArgumentNullException(nameof(httpClientFactory));
     _randomFactory     = randomFactory ?? throw new ArgumentNullException(nameof(randomFactory));
     _operationLogger   = operationLogger ?? throw new ArgumentNullException(nameof(operationLogger));
 }
Exemple #5
0
        /// <summary>
        /// Initializes a new instance of the <see cref="ClusterProber"/> class.
        /// HealthProber is the unit that checks the health state for all destinations(replica) of a cluster(service)
        /// HealthProbe would query the health controller of the destination and update the health state for every destination
        /// periodically base on the time interval user specified in cluster.
        /// </summary>
        public ClusterProber(string clusterId, ClusterConfig config, IDestinationManager destinationManager, IMonotonicTimer timer, ILogger <ClusterProber> logger, IOperationLogger <ClusterProber> operationLogger, HttpClient httpClient, IRandomFactory randomFactory)
        {
            ClusterId               = clusterId ?? throw new ArgumentNullException(nameof(clusterId));
            Config                  = config ?? throw new ArgumentNullException(nameof(config));
            _destinationManager     = destinationManager ?? throw new ArgumentNullException(nameof(destinationManager));
            _timer                  = timer ?? throw new ArgumentNullException(nameof(timer));
            _logger                 = logger ?? throw new ArgumentNullException(nameof(logger));
            _operationLogger        = operationLogger ?? throw new ArgumentNullException(nameof(operationLogger));
            _randomFactory          = randomFactory ?? throw new ArgumentNullException(nameof(randomFactory));
            _clusterProbeHttpClient = httpClient ?? throw new ArgumentNullException(nameof(httpClient));

            _healthControllerUrl = new Uri(Config.HealthCheckOptions.Path, UriKind.Relative);
            _healthCheckInterval = Config.HealthCheckOptions.Interval;
        }
        /// <summary>
        /// Initializes a new instance of the <see cref="BackendProber"/> class.
        /// HealthProber is the unit that checks the health state for all destinations(replica) of a backend(service)
        /// HealthProbe would query the health controller of the destination and update the health state for every destination
        /// periodically base on the time interval user specified in backend.
        /// </summary>
        public BackendProber(string backendId, BackendConfig config, IDestinationManager destinationManager, IMonotonicTimer timer, ILogger <BackendProber> logger, IOperationLogger <BackendProber> operationLogger, HttpClient httpClient, IRandomFactory randomFactory)
        {
            Contracts.CheckValue(backendId, nameof(backendId));
            Contracts.CheckValue(config, nameof(config));
            Contracts.CheckValue(destinationManager, nameof(destinationManager));
            Contracts.CheckValue(timer, nameof(timer));
            Contracts.CheckValue(logger, nameof(logger));
            Contracts.CheckValue(operationLogger, nameof(operationLogger));
            Contracts.CheckValue(httpClient, nameof(httpClient));
            Contracts.CheckValue(randomFactory, nameof(randomFactory));

            BackendId           = backendId;
            Config              = config;
            _destinationManager = destinationManager;
            _timer              = timer;
            _logger             = logger;
            _operationLogger    = operationLogger;
            _randomFactory      = randomFactory;

            _healthControllerUrl = new Uri(Config.HealthCheckOptions.Path, UriKind.Relative);
            _healthCheckInterval = Config.HealthCheckOptions.Interval;

            _backendProbeHttpClient = httpClient;
        }
            /// <summary>
            /// Start the execution of a work item.
            /// </summary>
            /// <param name="operationLogger">Instance of <see cref="IOperationLogger"/>.</param>
            /// <param name="monotonicTimer">Instance of <see cref="IMonotonicTimer"/>.</param>
            internal async void Start(IOperationLogger operationLogger, IMonotonicTimer monotonicTimer)
            {
                Contracts.Check(_isExecuting == false, "Expected work item was not executing");

                _isExecuting  = true;
                LastExecution = monotonicTimer.CurrentTime;
                try
                {
                    await operationLogger.ExecuteAsync(
                        OperationName,
                        async() =>
                    {
                        await Func(_cts.Token);
                    });
                }
                catch (Exception e) when(!e.IsFatal())
                {
                    // Exceptions are not expected, but are already logged above and service must remain executing.
                }
                finally
                {
                    _isExecuting = false;
                }
            }
        /// <summary>
        /// Operates like <see cref="CancellationTokenSource.CancelAfter(TimeSpan)"/> but supporting specifying a custom timer.
        /// </summary>
        /// <param name="cancellationTokenSource">Token to cancel after expiration is complete.</param>
        /// <param name="timeout">Timeout after which the cancellationTokenSource will be canceled.</param>
        /// <param name="timer">Timer to perform the measurement of time for determining when to cancel.</param>
        public static async void CancelAfter(this CancellationTokenSource cancellationTokenSource, TimeSpan timeout, IMonotonicTimer timer)
        {
            if (timer == null)
            {
                throw new ArgumentNullException(nameof(timer));
            }

            try
            {
                await timer.Delay(timeout, cancellationTokenSource.Token);

                cancellationTokenSource.Cancel();
            }
            catch (ObjectDisposedException)
            {
                // Ignore disposed cancellation tokens. Indicates cancellation is no longer needed. Unfortunately CTS's don't give a good
                // way to safely check async disposal, so must rely on exception handling instead.
            }
            catch (OperationCanceledException)
            {
                // It cts was canceled, then there's no need for us to cancel the token. Return successfully.
                // Note that we can't avoid this situation in advance as we strongly desire here to retain the 'void' returning
                // interface that cts.CancelAfter(ts) has.
            }
        }
Exemple #9
0
 /// <summary>
 /// Initializes a new instance of the <see cref="Cache{T}"/> class.
 /// </summary>
 /// <param name="timer">A timer to use to track expirations.</param>
 /// <param name="expirationTimeOffset">The time it takes for cache values to expire.</param>
 public Cache(IMonotonicTimer timer, TimeSpan expirationTimeOffset)
 {
     _timer = timer ?? throw new ArgumentNullException(nameof(timer));
     _expirationTimeOffset = expirationTimeOffset;
 }
Exemple #10
0
 internal bool Expired(IMonotonicTimer timer) => ExpirationTime < timer.CurrentTime;