/// <inheritdoc /> public async Task Handle(RetroactiveCommand <TCommand> iCommand) { if (iCommand.Timestamp == default) { iCommand.StoreInLog = false; await _handler.Handle(iCommand.Command); return; } _log.StopWatch.Start($"{nameof(RetroactiveCommandHandler<TCommand>)}"); iCommand.Command.Timestamp = iCommand.Timestamp; iCommand.Command.UseTimestamp = true; var time = iCommand.Timestamp; _log.StopWatch.Start("GetChanges_1"); var changes = await _retroactive.GetChanges(iCommand.Command, time); _log.StopWatch.Stop("GetChanges_1"); if (changes.Count == 0) { _log.StopWatch.Stop($"{nameof(RetroactiveCommandHandler<TCommand>)}"); iCommand.StoreInLog = false; return; } _log.StopWatch.Start("TryInsert_1"); var invalidEvents = await _retroactive.TryInsert(changes, time); _log.StopWatch.Stop("TryInsert_1"); if (invalidEvents.Count > 0) { var commands = await RollbackEvents(invalidEvents); changes = await _retroactive.GetChanges(iCommand.Command, time); await _retroactive.TryInsert(changes, time); foreach (var c in commands) { _log.Debug($"Replaying command {c.GetType().GetFriendlyName()} with timestamp {c.Timestamp}"); await _retroactive.ReplayCommand(c); } } await _commandLog.AppendCommand(iCommand.Command); iCommand.EventType = iCommand.Command.EventType; _messageQueue.Alert(new InvalidateProjections()); _log.StopWatch.Stop($"{nameof(RetroactiveCommandHandler<TCommand>)}"); }
/// <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); } }