Example #1
0
 private static ScheduledCommand CreateStoredScheduledCommand <TAggregate>(
     IScheduledCommand <TAggregate> scheduledCommand,
     DateTimeOffset domainTime,
     Clock schedulerClock)
     where TAggregate : class =>
 new ScheduledCommand
 {
     AggregateId    = ScheduledCommand <TAggregate> .TargetGuid(scheduledCommand),
     SequenceNumber = scheduledCommand
                      .IfTypeIs <IEvent>()
                      .Then(e => e.SequenceNumber)
                      .Else(() => - DateTimeOffset.UtcNow.Ticks),
     AggregateType     = Command.TargetNameFor(scheduledCommand.Command.GetType()),
     SerializedCommand = scheduledCommand.ToJson(),
     CreatedTime       = domainTime,
     DueTime           = scheduledCommand.DueTime ?? schedulerClock.Now(),
     Clock             = schedulerClock
 };
Example #2
0
        private async Task Enqueue(IScheduledCommand scheduledCommand)
        {
            var message = new BrokeredMessage(scheduledCommand.ToJson())
            {
                SessionId = scheduledCommand.AggregateId.ToString()
            };

            if (scheduledCommand.DueTime != null)
            {
                message.ScheduledEnqueueTimeUtc = scheduledCommand.DueTime.Value.UtcDateTime.Add(MessageDeliveryOffsetFromCommandDueTime);
            }

            messageSubject.OnNext(scheduledCommand);

            using (new TransactionScope(TransactionScopeOption.Suppress))
            {
                await queueClient.SendAsync(message);
            }
        }
        private async Task <ScheduledCommand> StoreScheduledCommand(IScheduledCommand <TAggregate> scheduledCommandEvent)
        {
            ScheduledCommand storedScheduledCommand;

            using (var db = createCommandSchedulerDbContext())
            {
                var domainTime = Domain.Clock.Now();

                // store the scheduled command
                var clockName = await ClockNameForEvent(scheduledCommandEvent, db);

                var schedulerClock = await db.Clocks.SingleOrDefaultAsync(c => c.Name == clockName);

                if (schedulerClock == null)
                {
                    Debug.WriteLine(string.Format("SqlCommandScheduler: Creating clock '{0}' @ {1}", clockName, domainTime));

                    schedulerClock = new Clock
                    {
                        Name      = clockName,
                        UtcNow    = domainTime,
                        StartTime = domainTime
                    };
                    db.Clocks.Add(schedulerClock);
                    await db.SaveChangesAsync();
                }

                storedScheduledCommand = new ScheduledCommand
                {
                    AggregateId       = scheduledCommandEvent.AggregateId,
                    SequenceNumber    = scheduledCommandEvent.SequenceNumber,
                    AggregateType     = eventStreamName,
                    SerializedCommand = scheduledCommandEvent.ToJson(),
                    CreatedTime       = domainTime,
                    DueTime           = scheduledCommandEvent.DueTime,
                    Clock             = schedulerClock
                };

                if (storedScheduledCommand.ShouldBeDeliveredImmediately() &&
                    !scheduledCommandEvent.Command.RequiresDurableScheduling)
                {
                    storedScheduledCommand.NonDurable = true;
                    return(storedScheduledCommand);
                }

                Debug.WriteLine(string.Format("SqlCommandScheduler: Storing command '{0}' ({1}:{2}) on clock '{3}'",
                                              scheduledCommandEvent.Command.CommandName,
                                              scheduledCommandEvent.AggregateId,
                                              scheduledCommandEvent.SequenceNumber,
                                              clockName));

                db.ScheduledCommands.Add(storedScheduledCommand);

                while (true)
                {
                    try
                    {
                        db.SaveChanges();
                        break;
                    }
                    catch (DbUpdateException exception)
                    {
                        if (exception.IsConcurrencyException())
                        {
                            if (storedScheduledCommand.SequenceNumber < 0)
                            {
                                // for scheduler-assigned sequence numbers, decrement and retry
                                storedScheduledCommand.SequenceNumber--;
                            }
                            else
                            {
                                // this is not a scheduler-assigned sequence number, so the concurrency exception indicates an actual issue
                                break;
                            }
                        }
                        else
                        {
                            throw;
                        }
                    }
                }
            }

            return(storedScheduledCommand);
        }
Example #4
0
        internal static async Task <ScheduledCommand> StoreScheduledCommand <TAggregate>(
            IScheduledCommand <TAggregate> scheduledCommand,
            Func <CommandSchedulerDbContext> createDbContext,
            Func <IScheduledCommand <TAggregate>, CommandSchedulerDbContext, Task <string> > clockNameForEvent) where TAggregate : class, IEventSourced
        {
            ScheduledCommand storedScheduledCommand;

            using (var db = createDbContext())
            {
                var domainTime = Domain.Clock.Now();

                // get or create a clock to schedule the command on
                var clockName = await clockNameForEvent(scheduledCommand, db);

                var schedulerClock = await db.Clocks.SingleOrDefaultAsync(c => c.Name == clockName);

                if (schedulerClock == null)
                {
                    Debug.WriteLine(String.Format("Creating clock '{0}' @ {1}", clockName, domainTime));

                    schedulerClock = new Clock
                    {
                        Name      = clockName,
                        UtcNow    = domainTime,
                        StartTime = domainTime
                    };
                    db.Clocks.Add(schedulerClock);
                    await db.SaveChangesAsync();
                }

                storedScheduledCommand = new ScheduledCommand
                {
                    AggregateId       = scheduledCommand.AggregateId,
                    SequenceNumber    = scheduledCommand.SequenceNumber,
                    AggregateType     = AggregateType <TAggregate> .EventStreamName,
                    SerializedCommand = scheduledCommand.ToJson(),
                    CreatedTime       = domainTime,
                    DueTime           = scheduledCommand.DueTime,
                    Clock             = schedulerClock
                };

                if (scheduledCommand.IsDue(storedScheduledCommand.Clock) &&
                    !scheduledCommand.Command.RequiresDurableScheduling)
                {
                    storedScheduledCommand.NonDurable = true;
                    return(storedScheduledCommand);
                }

                Debug.WriteLine(String.Format("Storing command '{0}' ({1}:{2}) on clock '{3}'",
                                              scheduledCommand.Command.CommandName,
                                              scheduledCommand.AggregateId,
                                              scheduledCommand.SequenceNumber,
                                              clockName));

                db.ScheduledCommands.Add(storedScheduledCommand);

                while (true)
                {
                    try
                    {
                        db.SaveChanges();
                        scheduledCommand.Result = new CommandScheduled(scheduledCommand)
                        {
                            ClockName = schedulerClock.Name
                        };
                        break;
                    }
                    catch (DbUpdateException exception)
                    {
                        if (exception.IsConcurrencyException())
                        {
                            if (storedScheduledCommand.SequenceNumber < 0)
                            {
                                // for scheduler-assigned sequence numbers, decrement and retry
                                storedScheduledCommand.SequenceNumber--;
                            }
                            else
                            {
                                // this is not a scheduler-assigned sequence number, so the concurrency exception indicates an actual issue
                                break;
                            }
                        }
                        else
                        {
                            throw;
                        }
                    }
                }
            }

            return(storedScheduledCommand);
        }
Example #5
0
        private ScheduledCommand StoreScheduledCommand(IScheduledCommand <TAggregate> scheduledCommandEvent)
        {
            ScheduledCommand storedScheduledCommand;

            using (var db = createCommandSchedulerDbContext())
            {
                var domainTime = Domain.Clock.Now();

                // store the scheduled command
                var clockName      = ClockNameForEvent(scheduledCommandEvent, db);
                var schedulerClock = db.Clocks.SingleOrDefault(c => c.Name == clockName);

                if (schedulerClock == null)
                {
                    schedulerClock = new Clock
                    {
                        Name      = clockName,
                        UtcNow    = domainTime,
                        StartTime = domainTime
                    };
                    db.Clocks.Add(schedulerClock);
                    db.SaveChanges();
                }

                storedScheduledCommand = new ScheduledCommand
                {
                    AggregateId       = scheduledCommandEvent.AggregateId,
                    SequenceNumber    = scheduledCommandEvent.SequenceNumber,
                    AggregateType     = eventStreamName,
                    SerializedCommand = scheduledCommandEvent.ToJson(),
                    CreatedTime       = domainTime,
                    DueTime           = scheduledCommandEvent.DueTime,
                    Clock             = schedulerClock
                };

                if (storedScheduledCommand.ShouldBeDeliveredImmediately() &&
                    !scheduledCommandEvent.Command.RequiresDurableScheduling)
                {
                    storedScheduledCommand.NonDurable = true;
                    return(storedScheduledCommand);
                }

                db.ScheduledCommands.Add(storedScheduledCommand);

                while (true)
                {
                    try
                    {
                        db.SaveChanges();
                        break;
                    }
                    catch (DbUpdateException exception)
                    {
                        if (exception.IsConcurrencyException())
                        {
                            if (storedScheduledCommand.SequenceNumber < 0)
                            {
                                // for scheduler-assigned sequence numbers, decrement and retry
                                storedScheduledCommand.SequenceNumber--;
                            }
                            else
                            {
                                // this is not a scheduler-assigned sequence number, so the concurrency exception indicates
                                break;
                            }
                        }
                        else
                        {
                            throw;
                        }
                    }
                }
            }

            return(storedScheduledCommand);
        }
        private async Task Enqueue(IScheduledCommand scheduledCommand)
        {
            var message = new BrokeredMessage(scheduledCommand.ToJson())
            {
                SessionId = scheduledCommand.AggregateId.ToString()
            };

            if (scheduledCommand.DueTime != null)
            {
                message.ScheduledEnqueueTimeUtc = scheduledCommand.DueTime.Value.UtcDateTime.Add(MessageDeliveryOffsetFromCommandDueTime);
            }

            messageSubject.OnNext(scheduledCommand);

            using (new TransactionScope(TransactionScopeOption.Suppress, TransactionScopeAsyncFlowOption.Enabled))
            {
                await queueClient.SendAsync(message);
            }
        }