private void HandleSendingFailure(State state, string batchId, IngestionException e) { var isRecoverable = e?.IsRecoverable ?? false; AppCenterLog.Error(AppCenterLog.LogTag, $"Sending logs for channel '{Name}', batch '{batchId}' failed: {e?.Message}"); List <Log> removedLogs; using (_mutex.GetLock(state)) { removedLogs = _sendingBatches[batchId]; _sendingBatches.Remove(batchId); if (isRecoverable) { _pendingLogCount += removedLogs.Count; } } if (!isRecoverable && FailedToSendLog != null) { foreach (var log in removedLogs) { FailedToSendLog?.Invoke(this, new FailedToSendLogEventArgs(log, e)); } } Suspend(state, !isRecoverable, e); }
private void HandleSendingFailure(State state, string batchId, Exception exception) { IList <Log> removedLogs; using (_mutex.GetLock(state)) { removedLogs = _sendingBatches[batchId]; _sendingBatches.Remove(batchId); } if (FailedToSendLog != null) { foreach (var log in removedLogs) { AppCenterLog.Debug(AppCenterLog.LogTag, $"Invoke FailedToSendLog event for channel '{Name}'"); FailedToSendLog?.Invoke(this, new FailedToSendLogEventArgs(log, exception)); } } try { _storage.DeleteLogs(Name, batchId); } catch (StorageException e) { AppCenterLog.Warn(AppCenterLog.LogTag, $"Could not delete logs for batch {batchId}", e); } }
public async Task EnqueueAsync(Log log) { try { State state; bool discardLogs; using (await _mutex.GetLockAsync().ConfigureAwait(false)) { state = _mutex.State; discardLogs = _discardLogs; } if (discardLogs) { AppCenterLog.Warn(AppCenterLog.LogTag, "Channel is disabled; logs are discarded"); SendingLog?.Invoke(this, new SendingLogEventArgs(log)); FailedToSendLog?.Invoke(this, new FailedToSendLogEventArgs(log, new CancellationException())); } EnqueuingLog?.Invoke(this, new EnqueuingLogEventArgs(log)); await PrepareLogAsync(log, state).ConfigureAwait(false); await PersistLogAsync(log, state).ConfigureAwait(false); } catch (StatefulMutexException) { AppCenterLog.Warn(AppCenterLog.LogTag, "The Enqueue operation has been cancelled"); } }
private void HandleSendingFailure(string batchId, IngestionException e) { var isRecoverable = e?.IsRecoverable ?? false; MobileCenterLog.Error(MobileCenterLog.LogTag, $"Sending logs for channel '{Name}', batch '{batchId}' failed", e); var removedLogs = _sendingBatches[batchId]; _sendingBatches.Remove(batchId); if (!isRecoverable && FailedToSendLog != null) { foreach (var log in removedLogs) { FailedToSendLog?.Invoke(this, new FailedToSendLogEventArgs(log, e)); } } _mutex.Lock(); try { Suspend(!isRecoverable, e); if (isRecoverable) { _pendingLogCount += removedLogs.Count; } } finally { _mutex.Unlock(); } }
private async Task SignalDeletingLogs(IList <string> sendingBatches) { var logs = new List <Log>(); try { do { var batchId = await _storage.GetLogsAsync(Name, ClearBatchSize, logs).ConfigureAwait(false); if (sendingBatches.Contains(batchId)) { continue; } foreach (var log in logs) { AppCenterLog.Debug(AppCenterLog.LogTag, $"Invoke SendingLog for channel '{Name}'"); SendingLog?.Invoke(this, new SendingLogEventArgs(log)); AppCenterLog.Debug(AppCenterLog.LogTag, $"Invoke FailedToSendLog event for channel '{Name}'"); FailedToSendLog?.Invoke(this, new FailedToSendLogEventArgs(log, new CancellationException())); } }while (logs.Count >= ClearBatchSize); } catch { AppCenterLog.Warn(AppCenterLog.LogTag, "Failed to invoke events for logs being deleted."); } }
public Task Enqueue(Log log) { _mutex.Lock(); var stateSnapshot = _stateKeeper.GetStateSnapshot(); try { if (_discardLogs) { MobileCenterLog.Warn(MobileCenterLog.LogTag, "Channel is disabled; logs are discarded"); _mutex.Unlock(); SendingLog?.Invoke(this, new SendingLogEventArgs(log)); FailedToSendLog?.Invoke(this, new FailedToSendLogEventArgs(log, new CancellationException())); return(null); } _mutex.Unlock(); EnqueuingLog?.Invoke(this, new EnqueuingLogEventArgs(log)); _mutex.Lock(stateSnapshot); return(Task.Run(async() => { await PrepareLogAsync(log).ConfigureAwait(false); await PersistLogAsync(log, stateSnapshot).ConfigureAwait(false); })); } catch (StatefulMutexException e) { MobileCenterLog.Warn(MobileCenterLog.LogTag, "The Enqueue operation has been cancelled", e); return(null); } finally { _mutex.Unlock(); } }
/// <summary> /// Suspend channel. /// </summary> /// <param name="state">Current state.</param> /// <param name="deleteLogs">Value indicating whether logs should be enabled or disabled.</param> /// <param name="exception">Possible error if unsuccessful.</param> /// <param name="needDisableChannel">Value indicating whether channel should be disabled. True by default.</param> private void Suspend(State state, bool deleteLogs, Exception exception, bool needDisableChannel = true) { AppCenterLog.Debug(AppCenterLog.LogTag, $"Suspend channel: '{Name}'"); try { IList <string> sendingBatches = null; IList <Log> unsentLogs = null; using (_mutex.GetLock(state)) { if (needDisableChannel) { _enabled = false; } _batchScheduled = false; _discardLogs = deleteLogs; if (deleteLogs) { sendingBatches = _sendingBatches.Keys.ToList(); unsentLogs = _sendingBatches.Values.SelectMany(batch => batch).ToList(); _sendingBatches.Clear(); } state = _mutex.InvalidateState(); } if (unsentLogs != null && FailedToSendLog != null) { foreach (var log in unsentLogs) { AppCenterLog.Debug(AppCenterLog.LogTag, $"Invoke FailedToSendLog event for channel '{Name}'"); FailedToSendLog?.Invoke(this, new FailedToSendLogEventArgs(log, exception)); } } if (deleteLogs) { IList <IServiceCall> calls; using (_mutex.GetLock(state)) { calls = _calls.ToList(); _calls.Clear(); _pendingLogCount = 0; TriggerDeleteLogsOnSuspending(sendingBatches); } foreach (var call in calls) { call.Cancel(); } } _storage.ClearPendingLogState(Name); } catch (StatefulMutexException) { AppCenterLog.Warn(AppCenterLog.LogTag, "The suspend operation has been canceled"); } }
private void Suspend(State state, bool deleteLogs, Exception exception) { try { IEnumerable <Log> unsentLogs = null; using (_mutex.GetLock(state)) { _enabled = false; _batchScheduled = false; _discardLogs = deleteLogs; if (deleteLogs) { unsentLogs = _sendingBatches.Values.SelectMany(batch => batch); _sendingBatches.Clear(); } state = _mutex.InvalidateState(); } if (unsentLogs != null) { foreach (var log in unsentLogs) { FailedToSendLog?.Invoke(this, new FailedToSendLogEventArgs(log, exception)); } } if (deleteLogs) { try { _ingestion.Close(); } catch (IngestionException e) { AppCenterLog.Error(AppCenterLog.LogTag, "Failed to close ingestion", e); } using (_mutex.GetLock(state)) { _pendingLogCount = 0; TriggerDeleteLogsOnSuspending(); } } _storage.ClearPendingLogState(Name); } catch (StatefulMutexException) { AppCenterLog.Warn(AppCenterLog.LogTag, "The Suspend operation has been cancelled"); } }
/// <summary> /// Enqueue a log asynchronously. /// </summary> /// <param name="log">log to enqueue.</param> /// <returns>The async Task for this operation.</returns> public async Task EnqueueAsync(Log log) { try { State state; bool discardLogs; using (await _mutex.GetLockAsync().ConfigureAwait(false)) { state = _mutex.State; discardLogs = _discardLogs; } if (discardLogs) { AppCenterLog.Warn(AppCenterLog.LogTag, "Channel is disabled; logs are discarded"); AppCenterLog.Debug(AppCenterLog.LogTag, $"Invoke SendingLog event for channel '{Name}'"); SendingLog?.Invoke(this, new SendingLogEventArgs(log)); AppCenterLog.Debug(AppCenterLog.LogTag, $"Invoke FailedToSendLog event for channel '{Name}'"); FailedToSendLog?.Invoke(this, new FailedToSendLogEventArgs(log, new CancellationException())); return; } AppCenterLog.Debug(AppCenterLog.LogTag, $"Invoke EnqueuingLog event for channel '{Name}'"); EnqueuingLog?.Invoke(this, new EnqueuingLogEventArgs(log)); await PrepareLogAsync(log, state).ConfigureAwait(false); AppCenterLog.Debug(AppCenterLog.LogTag, $"Invoke FilteringLog event for channel '{Name}'"); var filteringLogEventArgs = new FilteringLogEventArgs(log); FilteringLog?.Invoke(this, filteringLogEventArgs); if (filteringLogEventArgs.FilterRequested) { AppCenterLog.Warn(AppCenterLog.LogTag, $"Filtering out a log of type '{log.GetType()}' at the request of an event handler."); } else { await PersistLogAsync(log, state).ConfigureAwait(false); } } catch (StatefulMutexException) { AppCenterLog.Warn(AppCenterLog.LogTag, "The Enqueue operation has been canceled"); } }
private async Task SignalDeletingLogs(State stateSnapshot) { var logs = new List <Log>(); _mutex.Unlock(); await _storage.GetLogsAsync(Name, ClearBatchSize, logs).ConfigureAwait(false); await _mutex.LockAsync(stateSnapshot).ConfigureAwait(false); foreach (var log in logs) { _mutex.Unlock(); SendingLog?.Invoke(this, new SendingLogEventArgs(log)); FailedToSendLog?.Invoke(this, new FailedToSendLogEventArgs(log, new CancellationException())); await _mutex.LockAsync(stateSnapshot).ConfigureAwait(false); } if (logs.Count >= ClearBatchSize) { await SignalDeletingLogs(stateSnapshot).ConfigureAwait(false); } }
private Task Suspend(bool deleteLogs, Exception exception) { _enabled = false; _batchScheduled = false; _discardLogs = deleteLogs; _stateKeeper.InvalidateState(); var stateSnapshot = _stateKeeper.GetStateSnapshot(); try { if (deleteLogs && FailedToSendLog != null) { foreach (var log in _sendingBatches.Values.SelectMany(batch => batch)) { _mutex.Unlock(); FailedToSendLog?.Invoke(this, new FailedToSendLogEventArgs(log, exception)); _mutex.Lock(stateSnapshot); } } try { _ingestion.Close(); } catch (IngestionException e) { MobileCenterLog.Error(MobileCenterLog.LogTag, "Failed to close ingestion", e); } if (deleteLogs) { _pendingLogCount = 0; return(Task.Run(DeleteLogsOnSuspendedAsync)); } return(_storage.ClearPendingLogStateAsync(Name)); } catch (StatefulMutexException e) { MobileCenterLog.Warn(MobileCenterLog.LogTag, "The CountFromDisk operation has been cancelled", e); return(null); } }
private Task SignalDeletingLogs() { var logs = new List <Log>(); return(_storage.GetLogsAsync(Name, ClearBatchSize, logs) .ContinueWith(completedTask => { if (completedTask.IsFaulted) { AppCenterLog.Warn(AppCenterLog.LogTag, "Failed to invoke events for logs being deleted."); return; } foreach (var log in logs) { SendingLog?.Invoke(this, new SendingLogEventArgs(log)); FailedToSendLog?.Invoke(this, new FailedToSendLogEventArgs(log, new CancellationException())); } if (logs.Count >= ClearBatchSize) { SignalDeletingLogs(); } })); }
private void AnyChannelFailedToSendLog(object sender, FailedToSendLogEventArgs e) { FailedToSendLog?.Invoke(sender, e); }