/// <summary> /// Send transmissions in a loop. /// </summary> protected void SendLoop() { TimeSpan prevSendingInterval = TimeSpan.Zero; TimeSpan sendingInterval = _sendingIntervalOnNoData; try { while (!_stopped) { using (StorageTransmission transmission = _storage.Peek()) { if (_stopped) { // This second verification is required for cases where 'stopped' was set while peek was happening. // Once the actual sending starts the design is to wait until it finishes and deletes the transmission. // So no extra validation is required. break; } // If there is a transmission to send - send it. if (transmission != null) { bool shouldRetry = Send(transmission, ref sendingInterval); if (!shouldRetry) { // If retry is not required - delete the transmission. _storage.Delete(transmission); } } else { sendingInterval = _sendingIntervalOnNoData; } } LogInterval(prevSendingInterval, sendingInterval); DelayHandler.WaitOne(sendingInterval); prevSendingInterval = sendingInterval; } _stoppedHandler.Set(); } catch (ObjectDisposedException) { } }
private async Task SaveTransmissionToFileAsync(Transmission transmission, string file) { try { using (Stream stream = File.OpenWrite(Path.Combine(StorageFolder, file))) { await StorageTransmission.SaveAsync(transmission, stream).ConfigureAwait(false); } } catch (UnauthorizedAccessException) { string message = string.Format( "Failed to save transmission to file. UnauthorizedAccessException. File path: {0}, FileName: {1}", StorageFolder, file); PersistenceChannelDebugLog.WriteLine(message); throw; } }
private async Task <StorageTransmission> LoadTransmissionFromFileAsync(string file) { try { using (Stream stream = File.OpenRead(Path.Combine(StorageFolder, file))) { StorageTransmission storageTransmissionItem = await StorageTransmission.CreateFromStreamAsync(stream, file).ConfigureAwait(false); return(storageTransmissionItem); } } catch (Exception e) { string message = string.Format( "Failed to load transmission from file. File path: {0}, FileName: {1}, Exception: {2}", "storageFolderName", file, e); PersistenceChannelDebugLog.WriteLine(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-retryable error) it should be /// disposed. /// </summary> internal override StorageTransmission Peek() { IEnumerable <string> files = GetFiles("*.trn", 50); lock (_peekLockObj) { foreach (string file in files) { try { // if a file was peeked before, skip it (wait until it is disposed). if (PeekedTransmissions.ContainsKey(file) == false && _deletedFilesQueue.Contains(file) == false) { // Load the transmission from disk. StorageTransmission storageTransmissionItem = LoadTransmissionFromFileAsync(file) .ConfigureAwait(false).GetAwaiter().GetResult(); // when item is disposed it should be removed from the peeked list. storageTransmissionItem.Disposing = item => OnPeekedItemDisposed(file); // add the transmission to the list. PeekedTransmissions.Add(file, storageTransmissionItem.FullFilePath); return(storageTransmissionItem); } } catch (Exception e) { PersistenceChannelDebugLog.WriteException( e, "Failed to load an item from the storage. file: {0}", file); } } } return(null); }
/// <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>True, if there was sent error and we need to retry sending, otherwise false.</returns> protected virtual bool Send(StorageTransmission transmission, ref TimeSpan nextSendInterval) { try { if (transmission != null) { bool isConnected = NetworkInterface.GetIsNetworkAvailable(); // there is no internet connection available, return than. if (!isConnected) { PersistenceChannelDebugLog.WriteLine( "Cannot send data to the server. Internet connection is not available"); return(true); } transmission.SendAsync().ConfigureAwait(false).GetAwaiter().GetResult(); // After a successful sending, try immediately to send another transmission. nextSendInterval = SendingInterval; } } catch (WebException e) { int?statusCode = GetStatusCode(e); nextSendInterval = CalculateNextInterval(statusCode, nextSendInterval, _maxIntervalBetweenRetries); return(IsRetryable(statusCode, e.Status)); } catch (Exception e) { nextSendInterval = CalculateNextInterval(null, nextSendInterval, _maxIntervalBetweenRetries); PersistenceChannelDebugLog.WriteException(e, "Unknown exception during sending"); } return(false); }
internal abstract void Delete(StorageTransmission transmission);