Example #1
0
        /// <summary>
        /// It's recommended to use this method (or another TryAwaitOrTimeout or AwaitOrTimeout method)
        /// instead of just Task.WhenAny(taskToAwait, Task.Delay(timeout))
        /// because this method cancels the timer for timeout while <c>Task.Delay(timeout)</c>.
        /// If the number of “zombie” timer jobs starts becoming significant, performance could suffer.
        /// For more detailed explanation see https://devblogs.microsoft.com/pfxteam/crafting-a-task-timeoutafter-method/
        /// </summary>
        /// <returns><c>true</c> if <c>taskToAwait</c> completed before the timeout, <c>false</c> otherwise</returns>
        internal static async Task <bool> TryAwaitOrTimeout(this IAgentTimer agentTimer, Task taskToAwait
                                                            , AgentTimeInstant until, CancellationToken cancellationToken = default
                                                            )
        {
            var timeoutDelayCts  = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken);
            var timeoutDelayTask = agentTimer.Delay(until, timeoutDelayCts.Token);

            try
            {
                var completedTask = await Task.WhenAny(taskToAwait, timeoutDelayTask);

                if (completedTask == taskToAwait)
                {
                    // await taskToAwait to make it throw if taskToAwait is faulted or cancelled so it will throw as it should
                    await taskToAwait;
                    return(true);
                }

                Assertion.IfEnabled?.That(completedTask == timeoutDelayTask
                                          , $"{nameof(completedTask)}: {completedTask}, {nameof(timeoutDelayTask)}: timeOutTask, {nameof(taskToAwait)}: taskToAwait");
                // await timeout task in case it is cancelled and did not timed out so it will throw as it should
                await timeoutDelayTask;
                return(false);
            }
            finally
            {
                if (!timeoutDelayTask.IsCompleted)
                {
                    timeoutDelayCts.Cancel();
                }
                timeoutDelayCts.Dispose();
            }
        }
 internal CentralConfigFetcher(IApmLogger logger, IConfigStore configStore, ICentralConfigResponseParser centralConfigResponseParser,
                               Service service,
                               HttpMessageHandler httpMessageHandler = null, IAgentTimer agentTimer = null, string dbgName = null
                               ) : this(logger, configStore, configStore.CurrentSnapshot, service, httpMessageHandler, agentTimer, dbgName)
 {
     _centralConfigResponseParser = centralConfigResponseParser;
 }
Example #3
0
        /// <summary>
        /// We need this private ctor to avoid calling configStore.CurrentSnapshot twice (and thus possibly using different
        /// snapshots)
        /// when passing isEnabled: initialConfigSnapshot.CentralConfig and config: initialConfigSnapshot to base
        /// </summary>
        private CentralConfigFetcher(IApmLogger logger, IConfigStore configStore, IConfigSnapshot initialConfigSnapshot, Service service
                                     , HttpMessageHandler httpMessageHandler, IAgentTimer agentTimer, string dbgName
                                     )
            : base(/* isEnabled: */ initialConfigSnapshot.CentralConfig, logger, ThisClassName, service, initialConfigSnapshot, httpMessageHandler)
        {
            _logger = logger?.Scoped(ThisClassName + (dbgName == null ? "" : $" (dbgName: `{dbgName}')"));

            _initialSnapshot = initialConfigSnapshot;

            var isCentralConfigOptEqDefault = _initialSnapshot.CentralConfig == ConfigConsts.DefaultValues.CentralConfig;
            var centralConfigStatus         = _initialSnapshot.CentralConfig ? "enabled" : "disabled";

            if (!isCentralConfigOptEqDefault)
            {
                centralConfigStatus = centralConfigStatus.ToUpper();
            }
            _logger.IfLevel(isCentralConfigOptEqDefault ? LogLevel.Debug : LogLevel.Information)
            ?.Log("Central configuration feature is {CentralConfigStatus} because CentralConfig option's value is {CentralConfigOptionValue}"
                  + " (default value is {CentralConfigOptionDefaultValue})"
                  , centralConfigStatus, _initialSnapshot.CentralConfig, ConfigConsts.DefaultValues.CentralConfig);

            if (!_initialSnapshot.CentralConfig)
            {
                return;
            }

            _configStore = configStore;

            _agentTimer = agentTimer ?? new AgentTimer();

            _getConfigAbsoluteUrl = BackendCommUtils.ApmServerEndpoints.BuildGetConfigAbsoluteUrl(initialConfigSnapshot.ServerUrls.First(), service);
            _logger.Debug()
            ?.Log("Combined absolute URL for APM Server get central configuration endpoint: `{Url}'. Service: {Service}."
                  , _getConfigAbsoluteUrl, service);

            StartWorkLoop();
        }
Example #4
0
 internal bool IsCompatibleWith(IAgentTimer otherAgentTimer) => _sourceAgentTimer == otherAgentTimer;
Example #5
0
 internal AgentTimeInstant(IAgentTimer sourceAgentTimer, TimeSpan elapsedSinceTimerStarted)
 {
     _sourceAgentTimer         = sourceAgentTimer;
     _elapsedSinceTimerStarted = elapsedSinceTimerStarted;
 }
Example #6
0
        /// <summary>
        /// It's recommended to use this method (or another TryAwaitOrTimeout or AwaitOrTimeout method)
        /// instead of just Task.WhenAny(taskToAwait, Task.Delay(timeout))
        /// because this method cancels the timer for timeout while <c>Task.Delay(timeout)</c>.
        /// If the number of “zombie” timer jobs starts becoming significant, performance could suffer.
        /// For more detailed explanation see https://devblogs.microsoft.com/pfxteam/crafting-a-task-timeoutafter-method/
        /// </summary>
        /// <returns>
        /// (<c>true</c>, result of <c>taskToAwait</c>) if <c>taskToAwait</c> completed before the timeout, <c>false</c>
        /// otherwise
        /// </returns>
        internal static async Task <ValueTuple <bool, TResult> > TryAwaitOrTimeout <TResult>(this IAgentTimer agentTimer, Task <TResult> taskToAwait
                                                                                             , AgentTimeInstant until, CancellationToken cancellationToken = default
                                                                                             )
        {
            var hasTaskToAwaitCompletedBeforeTimeout =
                await TryAwaitOrTimeout(agentTimer, (Task)taskToAwait, until, cancellationToken);

            return(hasTaskToAwaitCompletedBeforeTimeout, hasTaskToAwaitCompletedBeforeTimeout ? await taskToAwait : default);
 internal CentralConfigFetcher(IApmLogger logger, IConfigStore configStore, Service service
                               , HttpMessageHandler httpMessageHandler = null, IAgentTimer agentTimer = null, string dbgName = null
                               )
     : this(logger, configStore, new CentralConfigResponseParser(logger), service, httpMessageHandler, agentTimer, dbgName)
 {
 }