/// <summary> Attempt to save this projection to the destination stream. </summary> /// <remarks> /// The returned task does not access the projection in any way, so the /// projection may be safely accessed before the task has finished executing. /// </remarks> /// <returns> /// True if saving was successful, false if it failed. /// </returns> public async Task <bool> TrySaveAsync(CancellationToken cancel = default) { if (_possiblyInconsistent) { _log?.Warning($"[{Name}] state is possibly inconsistent, not saving."); return(false); } if (_cacheProvider == null) { _log?.Warning($"[{Name}] no write cache provider !"); return(false); } var sequence = Sequence; var current = Current; _log?.Debug($"[{Name}] saving to seq {sequence}."); var sw = Stopwatch.StartNew(); var wrote = 0L; try { await _cacheProvider.TryWriteAsync(Name, async destination => { try { using (destination) { using (var wr = new BinaryWriter(destination, Encoding.UTF8, true)) wr.Write(sequence); if (!await _projection.TrySaveAsync(destination, current, cancel)) { _log?.Warning($"[{Name}] projection failed to save."); throw new Exception("INTERNAL.DO.NOT.SAVE"); } if (!destination.CanWrite) { throw new Exception("Projection saving closed the stream ! "); } using (var wr = new BinaryWriter(destination, Encoding.UTF8, true)) wr.Write(sequence); wrote = destination.Position; } } catch (Exception e) when(e.Message == "INTERNAL.DO.NOT.SAVE") { } catch (Exception e) { _log?.Warning($"[{Name}] while saving to cache.", e); throw new Exception("INTERNAL.DO.NOT.SAVE", e); } }).ConfigureAwait(false); if (wrote == 0) { _log?.Warning($"[{Name}] caching is disabled for this projection."); } else { _log?.Info($"[{Name}] saved {wrote} bytes to cache in {sw.Elapsed:mm':'ss'.'fff}."); } return(true); } catch (Exception e) when(e.Message == "INTERNAL.DO.NOT.SAVE") { // The inner function asked us not to save, and already logged the reason. // But if an inner exception is included, throw it (preserving the existing // stack trace). if (e.InnerException != null) { ExceptionDispatchInfo.Capture(e.InnerException).Throw(); } return(false); } catch (Exception ex) { _log?.Warning($"[{Name}] when opening write cache.", ex); return(false); } }
/// <summary> Attempt to save this projection to the destination stream. </summary> /// <remarks> /// The returned task does not access the object in any way, so the object /// may be safely accessed before the task has finished executing. /// </remarks> public async Task TrySaveAsync(CancellationToken cancel = default(CancellationToken)) { if (_possiblyInconsistent) { _log?.Warning($"[{Name}] state is possibly inconsistent, not saving."); return; } if (_cacheProvider == null) { _log?.Warning($"[{Name}] no write cache provider !"); return; } var sequence = Sequence; var current = Current; _log?.Debug($"[{Name}] saving to seq {sequence}."); Stream destination; var sw = Stopwatch.StartNew(); try { destination = await _cacheProvider.OpenWriteAsync(Name); } catch (Exception ex) { _log?.Warning($"[{Name}] when opening write cache.", ex); throw; } if (destination == null) { _log?.Warning($"[{Name}] caching is disabled for this projection."); return; } try { using (destination) { using (var wr = new BinaryWriter(destination, Encoding.UTF8, true)) wr.Write(sequence); if (!await _projection.TrySaveAsync(destination, current, cancel)) { _log?.Warning($"[{Name}] projection failed to save."); return; } if (!destination.CanWrite) { throw new Exception("Projection saving closed the stream ! "); } using (var wr = new BinaryWriter(destination, Encoding.UTF8, true)) wr.Write(sequence); } } catch (Exception e) { _log?.Warning($"[{Name}] while saving to cache.", e); throw; } _log?.Info($"[{Name}] saved in cache in {sw.Elapsed:mm':'ss'.'fff}."); }