public async Task Trigger(
     ScheduledCommand scheduled,
     SchedulerAdvancedResult result,
     CommandSchedulerDbContext db)
 {
     await deliver(scheduled, result, db);
 }
Beispiel #2
0
        internal async Task Trigger(
            ScheduledCommand scheduled,
            SchedulerAdvancedResult result,
            CommandSchedulerDbContext db)
        {
            var deliver = commandDispatchers.IfContains(scheduled.AggregateType)
                          .ElseDefault();

            if (deliver == null)
            {
                // QUESTION: (Trigger) is this worth raising a warning for or is there a reasonable chance that not registering a handler was deliberate?
                //                var error = ScheduledCommandFailure();
                //
                //                activity.OnNext(new CommandSchedulerActivity(scheduled, error));
                //
                //                result.Add(error);
                //                db.Errors.Add(error);
            }
            else
            {
                await deliver(scheduled);

                result.Add(scheduled.Result);
            }

            scheduled.Attempts++;

            await db.SaveChangesAsync();
        }
        private async Task <SchedulerAdvancedResult> Advance(string clockName,
                                                             DateTimeOffset?to = null,
                                                             TimeSpan?by       = null,
                                                             Func <IQueryable <ScheduledCommand>, IQueryable <ScheduledCommand> > query = null)
        {
            if (clockName == null)
            {
                throw new ArgumentNullException("clockName");
            }
            if (to == null && @by == null)
            {
                throw new ArgumentException("Either to or by must be specified.");
            }

            using (var db = createCommandSchedulerDbContext())
            {
                var clock = await db.Clocks.SingleOrDefaultAsync(c => c.Name == clockName);

                if (clock == null)
                {
                    throw new ObjectNotFoundException(string.Format("No clock named {0} was found.", clockName));
                }

                to = to ?? clock.UtcNow.Add(@by.Value);

                if (to < clock.UtcNow)
                {
                    throw new InvalidOperationException(string.Format("A clock cannot be moved backward. ({0})", new
                    {
                        Clock         = clock.ToJson(),
                        RequestedTime = to
                    }));
                }

                var result = new SchedulerAdvancedResult(to.Value);

                clock.UtcNow = to.Value;
                await db.SaveChangesAsync();

                var commands = db.ScheduledCommands
                               .Due(asOf: to)
                               .Where(c => c.Clock.Id == clock.Id);

                if (query != null)
                {
                    commands = query(commands);
                }

                // ToArray closes the connection so that when we perform saves during the loop there are no connection errors
                foreach (var scheduled in await commands.ToArrayAsync())
                {
                    //clock.UtcNow = scheduled.DueTime ?? to.Value;
                    await Trigger(scheduled, result, db);
                }

                return(result);
            }
        }
        private async Task<SchedulerAdvancedResult> Advance(
            string clockName,
            DateTimeOffset? to = null,
            TimeSpan? by = null,
            Func<IQueryable<ScheduledCommand>, IQueryable<ScheduledCommand>> query = null)
        {
            if (clockName == null)
            {
                throw new ArgumentNullException(nameof(clockName));
            }
            if (to == null && by == null)
            {
                throw new ArgumentException($"Either {nameof(to)} or {nameof(by)} must be specified.");
            }

            using (var db = createCommandSchedulerDbContext())
            {
                var clock = await db.Clocks.SingleOrDefaultAsync(c => c.Name == clockName);

                if (clock == null)
                {
                    throw new ObjectNotFoundException($"No clock named {clockName} was found.");
                }

                to = to ?? clock.UtcNow.Add(by.Value);

                if (to < clock.UtcNow)
                {
                    throw new InvalidOperationException($"A clock cannot be moved backward. ({new { Clock = clock.ToJson(), RequestedTime = to }})");
                }

                var result = new SchedulerAdvancedResult(to.Value);

                clock.UtcNow = to.Value;
                await db.SaveChangesAsync();

                var commands = db.ScheduledCommands
                                 .Due(asOf: to)
                                 .Where(c => c.Clock.Id == clock.Id);

                if (query != null)
                {
                    commands = query(commands);
                }

                // ToArray closes the connection so that when we perform saves during the loop there are no connection errors
                foreach (var scheduled in await commands.ToArrayAsync())
                {
                    await Configuration.Current.DeserializeAndDeliver(scheduled, db);
                    result.Add(scheduled.Result);
                }

                return result;
            }
        }
        /// <summary>
        /// Triggers all commands matched by the specified query.
        /// </summary>
        /// <param name="query">The query.</param>
        /// <returns>
        /// A result summarizing the triggered commands.
        /// </returns>
        /// <exception cref="System.ArgumentNullException">query</exception>
        /// <remarks>If the query matches commands that have been successfully applied already or abandoned, they will be re-applied.</remarks>
        public async Task<SchedulerAdvancedResult> Trigger(Func<IQueryable<ScheduledCommand>, IQueryable<ScheduledCommand>> query)
        {
            // QUESTION: (Trigger) re: the remarks XML comment, would it be clearer to have two methods, e.g. something like TriggerAnyCommands and TriggerEligibleCommands?
            if (query == null)
            {
                throw new ArgumentNullException(nameof(query));
            }

            var result = new SchedulerAdvancedResult();

            using (var db = createCommandSchedulerDbContext())
            {
                var commands = query(db.ScheduledCommands).ToArray();

                foreach (var scheduled in commands)
                {
                    await Trigger(scheduled, result, db);
                }
            }

            return result;
        }
        private async Task<SchedulerAdvancedResult> Advance(string clockName,
                                                            DateTimeOffset? to = null,
                                                            TimeSpan? by = null,
                                                            Func<IQueryable<ScheduledCommand>, IQueryable<ScheduledCommand>> query = null)
        {
            if (clockName == null)
            {
                throw new ArgumentNullException(nameof(clockName));
            }
            if (to == null && @by == null)
            {
                throw new ArgumentException($"Either {nameof(to)} or {nameof(by)} must be specified.");
            }

            using (var db = createCommandSchedulerDbContext())
            {
                var clock = await db.Clocks.SingleOrDefaultAsync(c => c.Name == clockName);

                if (clock == null)
                {
                    throw new ObjectNotFoundException($"No clock named {clockName} was found.");
                }

                to = to ?? clock.UtcNow.Add(@by.Value);

                if (to < clock.UtcNow)
                {
                    throw new InvalidOperationException($"A clock cannot be moved backward. ({new { Clock = clock.ToJson(), RequestedTime = to }})");
                }

                var result = new SchedulerAdvancedResult(to.Value);

                clock.UtcNow = to.Value;
                await db.SaveChangesAsync();

                var commands = db.ScheduledCommands
                                 .Due(asOf: to)
                                 .Where(c => c.Clock.Id == clock.Id);

                if (query != null)
                {
                    commands = query(commands);
                }

                // ToArray closes the connection so that when we perform saves during the loop there are no connection errors
                foreach (var scheduled in await commands.ToArrayAsync())
                {
                    await Trigger(scheduled, result, db);
                }

                return result;
            }
        }
 public async Task Trigger(
     ScheduledCommand scheduled,
     SchedulerAdvancedResult result,
     CommandSchedulerDbContext db) =>
         await deliver(scheduled, result, db);
        public override async Task When_triggering_specific_commands_then_the_result_can_be_used_to_evaluate_failures()
        {
            // arrange
            var target = new CommandTarget(Any.CamelCaseName());
            await store.Put(target);
            var schedulerAdvancedResult = new SchedulerAdvancedResult();

            // act
            await scheduler.Schedule(target.Id,
                                     new TestCommand(isValid: false),
                                     Clock.Now().AddDays(2));

            using (var db = Configuration.Current.CommandSchedulerDbContext())
            {
                var aggregateId = target.Id.ToGuidV3();
                var command = db.ScheduledCommands
                                .Single(c => c.AggregateId == aggregateId);

                await Configuration.Current
                                   .SchedulerClockTrigger()
                                   .Trigger(command, schedulerAdvancedResult, db);
            }

            //assert 
            schedulerAdvancedResult
                .FailedCommands
                .Should()
                .HaveCount(1);
        }
 public async Task Trigger(ScheduledCommand scheduled, SchedulerAdvancedResult result, CommandSchedulerDbContext db)
 {
     await ClockTrigger.Trigger(scheduled, result, db);
 }