private async Task RunUploader(CancellationToken cancellationToken) { TimeSpan errorDelay = _serverErrorBackoffSettings.Delay; while (true) { List <LogEntryExtra> entries; // Wait/loop until there are some log entries that need uploading. while (true) { DateTimeRange logEntriesLost; lock (_lockObj) { logEntriesLost = _logEntriesLost; _logEntriesLost = null; } entries = await _logQ.PeekAsync(_maxUploadBatchSize - (logEntriesLost != null ? 1 : 0), cancellationToken); 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); } // Upload entries to the Cloud Logging server try { await _client.WriteLogEntriesAsync(null, null, s_emptyLabels, entries.Select(x => x.Entry), cancellationToken); await _logQ.RemoveUntilAsync(entries.Last().Id, cancellationToken); lock (_lockObj) { _maxConfirmedSentId = entries.Last().Id; } _uploadCompleteEvent.Set(); errorDelay = _serverErrorBackoffSettings.Delay; } catch (Exception e) { // Always retry, regardless of error, as there's nothing much else to be done. await _scheduler.Delay(errorDelay, cancellationToken); errorDelay = new TimeSpan((long)(errorDelay.Ticks * _serverErrorBackoffSettings.DelayMultiplier)); if (errorDelay > _serverErrorBackoffSettings.MaxDelay) { errorDelay = _serverErrorBackoffSettings.MaxDelay; } // 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); } } }
private async Task RunUploader() { TimeSpan errorDelay = _serverErrorBackoffSettings.Delay; while (true) { IEnumerable <LogEntryExtra> entries; // Wait/loop until there are some log entries that need uploading. // TODO: See if log4net can be shutdown. If so, then this loop needs to terminate after // all log entries have been uploaded. while (true) { DateTimeRange logEntriesLost; lock (_lockObj) { logEntriesLost = _logEntriesLost; _logEntriesLost = null; } entries = await _logQ.PeekAsync(_maxUploadBatchSize - (logEntriesLost != null ? 1 : 0)); if (logEntriesLost != null) { var lostEntryExtra = new LogEntryExtra(-1, MakeLostEntry(logEntriesLost)); entries = (new[] { lostEntryExtra }).Concat(entries ?? Enumerable.Empty <LogEntryExtra>()); } if (entries != null && entries.Count() > 0) { // There are log entries that need uploading, so do that now. break; } await _uploadReadyEvent.WaitAsync(); } // Upload entries to the Cloud Logging server try { await _client.WriteLogEntriesAsync("", null, s_emptyLabels, entries.Select(x => x.Entry)); await _logQ.RemoveUntilAsync(entries.Last().Id); _emptyEvent.Set(); errorDelay = _serverErrorBackoffSettings.Delay; } catch (Exception) { // Always retry, regardless of error, as there's nothing much else to be done. await _scheduler.Delay(errorDelay); errorDelay = errorDelay.Scale(_serverErrorBackoffSettings.DelayMultiplier); if (errorDelay > _serverErrorBackoffSettings.MaxDelay) { errorDelay = _serverErrorBackoffSettings.MaxDelay; } } } }
// 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); } } }