/// <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; }
/// <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)); }
/// <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. } }
/// <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; }
internal bool Expired(IMonotonicTimer timer) => ExpirationTime < timer.CurrentTime;