/// <summary> /// Builds transmission from the file object. In the case of success adds /// new transmission to the processing queue. No exceptions are thrown. /// </summary> /// <param name="file">Valid FileInfo object</param> /// <returns>StorageTransmission object in case of success or null in case of fail</returns> private StorageTransmission BuildTransmissionFromFile(FileInfo file) { try { string text = BuildNewFullFileNameWithSameDate(file.Name); File.Move(file.FullName, text); FileInfo newfile = new FileInfo(text); StorageTransmission result = LoadTransmissionFromFileAsync(newfile).ConfigureAwait(false).GetAwaiter().GetResult(); if (LocalFileLoggerService.Default.Enabled) { LocalFileLoggerService.Default.Log(LocalLoggerSeverity.Info, "Telemetry", string.Format(CultureInfo.InvariantCulture, "Transmission ({0}): PersistenceStorageBase.BuildTransmissionFromFile renamed file from {1} to {2}", new object[3] { result, file.Name, newfile.Name })); } result.Disposing = delegate { OnPeekedItemDisposed(newfile.Name); }; peekedTransmissions.Add(newfile.Name, newfile.FullName); return(result); } catch (Exception ex) { string message = string.Format(CultureInfo.InvariantCulture, "Failed to load an item from the storage. file: {0} Exception: {1}", new object[2] { file, ex }); CoreEventSource.Log.LogVerbose(message); } return(null); }
private static async Task SaveTransmissionToFileAsync(Transmission transmission, string fileFullName) { try { using (Stream stream = File.OpenWrite(fileFullName)) { if (LocalFileLoggerService.Default.Enabled) { LocalFileLoggerService.Default.Log(LocalLoggerSeverity.Info, "Telemetry", string.Format(CultureInfo.InvariantCulture, "Transmission ({0}): PersistenceStorageBase.SaveTransmissionToFileAsync to file {1}", new object[2] { transmission, Path.GetFileName(fileFullName) })); } await StorageTransmission.SaveAsync(transmission, stream).ConfigureAwait(false); } } catch (UnauthorizedAccessException) { string message = $"Failed to save transmission to file. UnauthorizedAccessException. File full path: {fileFullName}"; CoreEventSource.Log.LogVerbose(message); LocalFileLoggerService.Default.Log(LocalLoggerSeverity.Error, "Telemetry", string.Format(CultureInfo.InvariantCulture, "Transmission ({0}): PersistenceStorageBase.SaveTransmissionToFileAsync UnauthorizedAccessException", new object[1] { transmission })); throw; } }
/// <summary> /// Peek all transmissions at once. /// </summary> /// <param name="token">Cancellation token</param> /// <returns>List of transmissions or empty array</returns> internal override IEnumerable <StorageTransmission> PeekAll(CancellationToken token) { List <StorageTransmission> list = new List <StorageTransmission>(); lock (peekLockObj) { foreach (FileInfo filteredFile in GetFilteredFiles()) { token.ThrowIfCancellationRequested(); StorageTransmission storageTransmission = BuildTransmissionFromFile(filteredFile); if (storageTransmission != null) { list.Add(storageTransmission); } } } if (LocalFileLoggerService.Default.Enabled) { LocalFileLoggerService.Default.Log(LocalLoggerSeverity.Info, "Telemetry", string.Format(CultureInfo.InvariantCulture, "PersistenceStorageBase.PeekAll peeked {0} transmissions", new object[1] { list.Count })); } return(list); }
/// <summary> /// Sends a transmission and handle errors. /// </summary> /// <param name="transmission">The transmission to send.</param> /// <param name="nextSendInterval">When this value returns it will hold a recommendation for when to start the next sending iteration.</param> /// <returns>A boolean value that indicates if there was a retriable error.</returns> protected virtual bool Send(StorageTransmission transmission, ref TimeSpan nextSendInterval) { Tuple <bool, TimeSpan> result = SendAsync(transmission, default(CancellationToken), nextSendInterval).ConfigureAwait(false).GetAwaiter().GetResult(); nextSendInterval = result.Item2; return(result.Item1); }
/// <summary> /// Send transmissions in a loop. /// </summary> protected void SendLoop() { TimeSpan prevSendInterval = TimeSpan.Zero; TimeSpan nextSendInterval = sendingIntervalOnNoData; try { for (; !stopped; LogInterval(prevSendInterval, nextSendInterval), DelayHandler.WaitOne(nextSendInterval), prevSendInterval = nextSendInterval) { using (StorageTransmission storageTransmission = storage.Peek()) { if (!stopped) { if (storageTransmission != null) { if (LocalFileLoggerService.Default.Enabled) { LocalFileLoggerService.Default.Log(LocalLoggerSeverity.Info, "Telemetry", string.Format(CultureInfo.InvariantCulture, "Transmission ({0}): PersistenceTransmitter.SendLoop about to send", new object[1] { storageTransmission })); } bool flag = Send(storageTransmission, ref nextSendInterval); if (LocalFileLoggerService.Default.Enabled) { LocalFileLoggerService.Default.Log(LocalLoggerSeverity.Info, "Telemetry", string.Format(CultureInfo.InvariantCulture, "Transmission ({0}): PersistenceTransmitter.SendLoop shouldRetry == {1}", new object[2] { storageTransmission, flag })); } if (!flag) { storage.Delete(storageTransmission); } } else { nextSendInterval = sendingIntervalOnNoData; } continue; } } break; } stoppedHandler.Set(); } catch (ObjectDisposedException) { } }
internal override void Delete(StorageTransmission item) { if (StorageFolder != null) { filesToDelete[item.FileName] = item.FullFilePath; if (LocalFileLoggerService.Default.Enabled) { LocalFileLoggerService.Default.Log(LocalLoggerSeverity.Info, "Telemetry", string.Format(CultureInfo.InvariantCulture, "Transmission ({0}): PersistenceStorageBase.Delete try to delete transmission", new object[1] { item })); } TryRemoveFilesToDelete(); } }
private static async Task <StorageTransmission> LoadTransmissionFromFileAsync(FileInfo file) { try { using (Stream stream = file.OpenRead()) { return(await StorageTransmission.CreateFromStreamAsync(stream, file.FullName).ConfigureAwait(false)); } } catch (Exception arg) { string message = $"Failed to load transmission from file. File full path: {file.FullName}, Exception: {arg}"; CoreEventSource.Log.LogVerbose(message); throw; } }
/// <summary> /// Reads an item from the storage. Order is Last-In-First-Out. /// When the Transmission is no longer needed (it was either sent or failed with a non-retriable error) it should be disposed. /// </summary> /// <returns></returns> internal override StorageTransmission Peek() { lock (peekLockObj) { foreach (FileInfo filteredFile in GetFilteredFiles()) { StorageTransmission storageTransmission = BuildTransmissionFromFile(filteredFile); if (storageTransmission != null) { if (LocalFileLoggerService.Default.Enabled) { LocalFileLoggerService.Default.Log(LocalLoggerSeverity.Info, "Telemetry", string.Format(CultureInfo.InvariantCulture, "Transmission ({0}): PersistenceStorageBase.Peek peeked transmission", new object[1] { storageTransmission })); } return(storageTransmission); } } } return(null); }
internal abstract void Delete(StorageTransmission transmission);
/// <summary> /// Sends a transmission asynchronously and handle errors. /// </summary> /// <param name="transmission">The transmission to send.</param> /// <param name="token">Cancellation token</param> /// <param name="sendInterval">Previous send interval duration</param> /// <returns></returns> private async Task <Tuple <bool, TimeSpan> > SendAsync(StorageTransmission transmission, CancellationToken token, TimeSpan sendInterval) { bool isRetryable = false; try { if (transmission != null) { bool flag = true; lock (hashLock) { flag = !setOfTransmissionHash.ContainsKey(transmission.ContentHash); if (flag) { setOfTransmissionHash[transmission.ContentHash] = listOfTransmissionHash.AddLast(Tuple.Create(DateTime.UtcNow, transmission.ContentHash)); checkStaleHashCount++; if (checkStaleHashCount >= 50) { CleanupStaleTransmissionHash(); checkStaleHashCount = 0; } } } if (flag) { await transmission.SendAsync(token).ConfigureAwait(false); } sendInterval = SendingInterval; } } catch (WebException ex) { int?statusCode = GetStatusCode(ex); sendInterval = CalculateNextInterval(statusCode, sendInterval, maxIntervalBetweenRetries); isRetryable = IsRetryable(statusCode, ex.Status); LocalFileLoggerService.Default.Log(LocalLoggerSeverity.Error, "Telemetry", string.Format(CultureInfo.InvariantCulture, "Transmission ({0}): PersistenceTransmitter.SendAsync WebException ({1}), isRetryable == {2}", new object[3] { transmission, ex.Message, isRetryable })); } catch (Exception ex2) { sendInterval = CalculateNextInterval(null, sendInterval, maxIntervalBetweenRetries); string message = string.Format(CultureInfo.InvariantCulture, "Unknown exception during sending: {0}", new object[1] { ex2 }); CoreEventSource.Log.LogVerbose(message); LocalFileLoggerService.Default.Log(LocalLoggerSeverity.Error, "Telemetry", string.Format(CultureInfo.InvariantCulture, "Transmission ({0}): PersistenceTransmitter.SendAsync Exception ({1})", new object[2] { transmission, ex2.Message })); if (ex2 is OperationCanceledException) { throw; } } if (isRetryable) { lock (hashLock) { LinkedListNode <Tuple <DateTime, string> > value = null; if (setOfTransmissionHash.TryGetValue(transmission.ContentHash, out value) && value != null) { listOfTransmissionHash.Remove(value); setOfTransmissionHash.Remove(transmission.ContentHash); } } } return(Tuple.Create(isRetryable, sendInterval)); }