Example #1
0
        // Note: calls to ConfigureAwait(false) aren't strictly required here,
        // as this method is only ever called in Task.Run, so there won't be a synchronization
        // context, but it's simple and harmless to make it "obviously okay".
        private async Task RunUploader(CancellationToken cancellationToken)
        {
            TimeSpan errorDelay = _serverErrorRetrySettings.InitialBackoff;

            while (true)
            {
                List <LogEntryExtra> entries;
                // Wait/loop until there are some log entries that need uploading.
                while (true)
                {
                    var peek = await _logQ.PeekAsync(_maxUploadBatchSize, cancellationToken).ConfigureAwait(false);

                    var logEntriesLost = peek.Lost;
                    entries = peek.Entries;
                    if (logEntriesLost != null)
                    {
                        var lostEntryExtra = new LogEntryExtra(-1, MakeLostEntry(logEntriesLost));
                        entries = (new[] { lostEntryExtra }).Concat(entries ?? Enumerable.Empty <LogEntryExtra>()).ToList();
                    }
                    if (entries != null && entries.Count() > 0)
                    {
                        // There are log entries that need uploading, so do that now.
                        break;
                    }
                    await _uploadReadyEvent.WaitAsync(cancellationToken).ConfigureAwait(false);
                }
                // Upload entries to the Cloud Logging server
                try
                {
                    await _client.WriteLogEntriesAsync((LogName)null, null, s_emptyLabels, entries.Select(x => x.Entry), cancellationToken).ConfigureAwait(false);

                    await _logQ.RemoveUntilAsync(entries.Last().Id, cancellationToken).ConfigureAwait(false);

                    lock (_lock)
                    {
                        _maxConfirmedSentId = entries.Last().Id;
                    }
                    _uploadCompleteEvent.Set();
                    errorDelay = _serverErrorRetrySettings.InitialBackoff;
                }
                catch (Exception e)
                {
                    // Always retry, regardless of error, as there's nothing much else to be done.
                    await _scheduler.Delay(errorDelay, cancellationToken).ConfigureAwait(false);

                    // TODO: Try to use RetryAttempt for this.
                    errorDelay = _serverErrorRetrySettings.NextBackoff(errorDelay);
                    // Use log4net internal logging to warn user of upload error.
                    // Internal logging can be enabled as described in the "Troubleshooting" section of the log4net FAQ.
                    log4net.Util.LogLog.Warn(typeof(LogUploader), "Error uploading log messages to server.", e);
                }
            }
        }
        public void NextBackoff(double current, double expectedNext)
        {
            var settings = new RetrySettings(
                maxAttempts: 5,
                initialBackoff: TimeSpan.FromSeconds(1.0),
                maxBackoff: TimeSpan.FromSeconds(5.0),
                backoffMultiplier: 2.0,
                e => true,
                RetrySettings.NoJitter);

            var expected = TimeSpan.FromSeconds(expectedNext);
            var actual   = settings.NextBackoff(TimeSpan.FromSeconds(current));

            Assert.Equal(expected, actual);
        }