public CommandScheduler( Func <IStore <TAggregate> > getStore, IETagChecker etagChecker) { if (getStore == null) { throw new ArgumentNullException(nameof(getStore)); } if (etagChecker == null) { throw new ArgumentNullException(nameof(etagChecker)); } this.getStore = getStore; this.etagChecker = etagChecker; }
/// <summary> /// Determines whether the command's precondition is satisfied, if it has one. /// </summary> /// <param name="preconditionChecker">The precondition checker.</param> /// <param name="scheduledCommand">The scheduled command.</param> /// <returns>True if the command has no precondition, or if its precondition is satisfied.</returns> /// <exception cref="System.ArgumentNullException"></exception> public static async Task <bool> IsPreconditionSatisfied( this IETagChecker preconditionChecker, IScheduledCommand scheduledCommand) { if (preconditionChecker == null) { throw new ArgumentNullException(nameof(preconditionChecker)); } var precondition = scheduledCommand.DeliveryPrecondition; if (precondition == null) { return(true); } return(await preconditionChecker.HasBeenRecorded( precondition.Scope, precondition.ETag)); }
internal static async Task ApplyScheduledCommand <TAggregate>( this IStore <TAggregate> store, IScheduledCommand <TAggregate> scheduled, IETagChecker preconditionChecker = null) where TAggregate : class { TAggregate aggregate = null; Exception exception; try { if (preconditionChecker != null && !await preconditionChecker.IsPreconditionSatisfied(scheduled)) { await FailScheduledCommand(store, scheduled, new PreconditionNotMetException(scheduled.DeliveryPrecondition)); return; } aggregate = await store.Get(scheduled.TargetId); var isConstructorCommand = scheduled.Command is ConstructorCommand <TAggregate>; if (aggregate == null) { if (isConstructorCommand) { var ctor = typeof(TAggregate).GetConstructor(new[] { scheduled.Command.GetType() }); if (ctor == null) { throw new InvalidOperationException($"No constructor was found on type {typeof (TAggregate)} for constructor command {scheduled.Command}."); } aggregate = (TAggregate)ctor.Invoke(new[] { scheduled.Command }); } else { throw new PreconditionNotMetException( $"No {typeof (TAggregate).Name} was found with id {scheduled.TargetId} so the command could not be applied."); } } else if (isConstructorCommand) { throw new ConcurrencyException($"Command target having id {scheduled.TargetId} already exists"); } else { await aggregate.ApplyAsync(scheduled.Command); } await store.Put(aggregate); scheduled.Result = new CommandSucceeded(scheduled); return; } catch (Exception ex) { exception = ex; } await FailScheduledCommand(store, scheduled, exception, aggregate); }