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(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; } }