// Grabs a snapshot of the current internal state, and starts a new task to send it to the server. private void StartFlush(EventBuffer buffer) { if (_disabled) { return; } FlushPayload payload = buffer.GetPayload(); if (payload.Events.Length > 0 || !payload.Summary.Empty) { lock (_flushWorkersCounter) { // Note that this counter will be 1, not 0, when there are no active flush workers. // This is because a .NET CountdownEvent can't be reused without explicitly resetting // it once it has gone to zero. if (_flushWorkersCounter.CurrentCount >= MaxFlushWorkers + 1) { // We already have too many workers, so just leave the events as is return; } // We haven't hit the limit, we'll go ahead and start a flush task _flushWorkersCounter.AddCount(1); } buffer.Clear(); Task.Run(() => FlushEventsAsync(payload)); } }
private async Task FlushEventsAsync(FlushPayload payload) { EventOutputFormatter formatter = new EventOutputFormatter(_config); var cts = new CancellationTokenSource(_config.HttpClientTimeout); List <EventOutput> eventsOut; string jsonEvents; try { eventsOut = formatter.MakeOutputEvents(payload.Events, payload.Summary); jsonEvents = JsonConvert.SerializeObject(eventsOut, Formatting.None); } catch (Exception e) { DefaultEventProcessor.Log.ErrorFormat("Error preparing events, will not send: {0}", e, Util.ExceptionMessage(e)); return; } try { await SendEventsAsync(jsonEvents, eventsOut.Count, cts); } catch (Exception e) { DefaultEventProcessor.Log.DebugFormat("Error sending events: {0}; waiting 1 second before retrying.", e, Util.ExceptionMessage(e)); Task.Delay(TimeSpan.FromSeconds(1)).Wait(); cts = new CancellationTokenSource(_config.HttpClientTimeout); try { await SendEventsAsync(jsonEvents, eventsOut.Count, cts); } catch (TaskCanceledException tce) { if (tce.CancellationToken == cts.Token) { //Indicates the task was cancelled by something other than a request timeout DefaultEventProcessor.Log.ErrorFormat("Error submitting events using uri: '{0}' '{1}'", tce, _uri.AbsoluteUri, Util.ExceptionMessage(tce)); } else { //Otherwise this was a request timeout. DefaultEventProcessor.Log.ErrorFormat("Timed out trying to send {0} events after {1}", tce, eventsOut.Count, _config.HttpClientTimeout); } } catch (Exception ex) { DefaultEventProcessor.Log.ErrorFormat("Error submitting events using uri: '{0}' '{1}'", ex, _uri.AbsoluteUri, Util.ExceptionMessage(ex)); } } _flushWorkersCounter.Signal(); }
private async Task FlushEventsAsync(FlushPayload payload) { EventOutputFormatter formatter = new EventOutputFormatter(_config); string jsonEvents; int eventCount; const int maxAttempts = 2; try { jsonEvents = formatter.SerializeOutputEvents(payload.Events, payload.Summary, out eventCount); } catch (Exception e) { DefaultEventProcessor.Log.ErrorFormat("Error preparing events, will not send: {0}", e, Util.ExceptionMessage(e)); return; } string payloadId = Guid.NewGuid().ToString(); for (var attempt = 0; attempt < maxAttempts; attempt++) { if (attempt > 0) { await Task.Delay(TimeSpan.FromSeconds(1)); } using (var cts = new CancellationTokenSource(_config.HttpClientTimeout)) { string errorMessage = null; bool canRetry = false; try { await SendEventsAsync(jsonEvents, eventCount, payloadId, cts.Token); return; // success } catch (TaskCanceledException e) { if (e.CancellationToken == cts.Token) { // Indicates the task was cancelled deliberately somehow; in this case don't retry DefaultEventProcessor.Log.Warn("Event sending task was cancelled"); return; } else { // Otherwise this was a request timeout. errorMessage = "Timed out"; canRetry = true; } } catch (UnsuccessfulResponseException e) { errorMessage = Util.HttpErrorMessageBase(e.StatusCode); if (Util.IsHttpErrorRecoverable(e.StatusCode)) { canRetry = true; } else { _disabled = true; // for error 401, etc. } } catch (Exception e) { errorMessage = string.Format("Error ({0})", Util.DescribeException(e)); canRetry = true; } string nextStepDesc = canRetry ? (maxAttempts == maxAttempts - 1 ? "will not retry" : "will retry after one second") : "giving up permanently"; DefaultEventProcessor.Log.WarnFormat(errorMessage + " sending {0} event(s); {1}", eventCount, nextStepDesc); if (!canRetry) { return; } } } }
private async Task FlushEventsAsync(FlushPayload payload) { EventOutputFormatter formatter = new EventOutputFormatter(_config); string jsonEvents; int eventCount; const int maxAttempts = 2; try { jsonEvents = formatter.SerializeOutputEvents(payload.Events, payload.Summary, out eventCount); } catch (Exception e) { DefaultEventProcessor.Log.ErrorFormat("Error preparing events, will not send: {0}", e, Util.ExceptionMessage(e)); return; } for (var attempt = 0; attempt < maxAttempts; attempt++) { if (attempt > 0) { await Task.Delay(TimeSpan.FromSeconds(1)); } using (var cts = new CancellationTokenSource(_config.HttpClientTimeout)) { try { await SendEventsAsync(jsonEvents, eventCount, cts.Token); return; // success } catch (Exception e) { var errorMessage = "Error ({2})"; switch (e) { case TaskCanceledException tce: if (tce.CancellationToken == cts.Token) { // Indicates the task was cancelled deliberately somehow; in this case don't retry DefaultEventProcessor.Log.Warn("Event sending task was cancelled"); return; } else { // Otherwise this was a request timeout. errorMessage = "Timed out"; } break; default: break; } DefaultEventProcessor.Log.WarnFormat(errorMessage + " sending {0} event(s); {1}", eventCount, attempt == maxAttempts - 1 ? "will not retry" : "will retry after one second", Util.ExceptionMessage(e)); } } } }