/// <inheritdoc /> public async Task<Dictionary<IStream, IEnumerable<IEvent>>> GetChanges(ICommand command, Time time) { var activeBranch = _manager.ActiveBranch; var branch = $"{command.GetType().Name}-{time.ToUnixTimeMilliseconds()}"; await _manager.Branch(branch, time, deleteExisting: true); var copy = command; copy.Timeline = branch; var handler = _commandRegistry.GetHandler(copy); if (handler == null) throw new InvalidOperationException($"No handler found for command {command.GetType().Name}"); await handler.Handle(copy); await _manager.Branch(activeBranch); var dict = new Dictionary<IStream, IEnumerable<IEvent>>(); var changes = await _manager.GetChanges(branch); _log.StopWatch.Start("GetChanges.Read"); foreach (var c in changes) { var stream = await _streamLocator.FindBranched(c.Key, branch); var e = await _eventStore.ReadStream<IEvent>(stream, stream.Version - c.Value + 1, c.Value).ToList(); dict[c.Key] = e; } _log.StopWatch.Stop("GetChanges.Read"); await _manager.DeleteBranch(branch); return dict; }
/// <inheritdoc /> protected override BranchState[] GetStates(BranchState current) { var activeBranch = _manager.ActiveBranch; var commands = GetCommands(current).ToList(); var states = new BranchState[commands.Count]; var iState = 0; foreach (var command in commands) { states[iState] = ApplyCommands(command, current.Timeline).Result; iState++; } _manager.Branch(activeBranch).Wait(); return(states); }
/// <summary> /// Branch mutation /// </summary> /// <param name="branch">Branch id</param> /// <returns>Branch result</returns> public bool Branch(string branch) { if (branch == string.Empty) { _manager.Reset(); } else { _manager.Branch(branch).Wait(); } return(true); }
/// <inheritdoc /> /// <summary> /// Wrap the handler and redirect all exception to <see cref="IErrorLog"/> /// </summary> public async Task Handle(T command) { _log.Trace($"{command.GetType().Name}", this); var timeline = _timeline.Id; if (!(command is IRetroactiveCommand) && command.Timestamp == default) { command.Timestamp = _timeline.Now; } if (command.LocalId == default) { command.LocalId = new EventId(Configuration.ReplicaName, command.Timestamp); } if (command.OriginId == default) { command.OriginId = new EventId(Configuration.ReplicaName, command.Timestamp); } command.Timeline = timeline; try { await _handler.Handle(command); if (command.StoreInLog && !command.Pure) { await _commandLog.AppendCommand(command); } } catch (Exception e) { _errorLog.Add(e); // check that we didn't end up on wrong timeline if (_timeline.Id != timeline) { var tException = new InvalidOperationException($"Execution started on {timeline} but ended on {_timeline.Id}"); _errorLog.Add(tException); // throw tException; await _branchManager.Branch(timeline); } await _commandLog.AddFailedCommand(command); } }