예제 #1
0
        private static async Task Execute(IServiceProvider services, IContext context, Command command)
        {
            QueueCommandResult result = await services
                                        .Send <QueueCommand, Task <QueueCommandResult> >(new QueueCommand(command, context))
                                        .To <ICommandProcessor>();

            await result.Completion;
        }
예제 #2
0
            public QueueOperationDebouncer()
            {
                Register((QueueCommand q) => {
                    return(_currentCommands.TryAdd(q.Command.ID, Nothing.Value) ?
                           Next(q) :
                           Task.FromResult(QueueCommandResult.AlreadyProcessing()));
                });

                Register(async(ExecuteCommand e) => {
                    try {
                        await Next(e).Get();
                    } finally {
                        _currentCommands.TryRemove(e.Command.ID, out _);
                    }
                });
            }
예제 #3
0
        private async Task Handle(RunScript script, IContext context)
        {
            foreach (ScriptCommand scriptCommand in script.Script.Commands)
            {
                using (TransactionScope scope = new TransactionScope(_services, context)) {
                    scope
                    .Context
                    .Set(new RequestTimeContext(DateTime.Now), true);

                    Command command = new Command(
                        scriptCommand.ID,
                        scriptCommand.Message,
                        scriptCommand.Target);

                    QueueCommandResult result = await _services
                                                .Send <QueueCommand, Task <QueueCommandResult> >(new QueueCommand(command, scope.Context))
                                                .To <ICommandProcessor>();

                    await result.Completion;
                }
            }
        }
예제 #4
0
            public CommandPersister(
                IServiceProvider services,
                ICommandMetadataProvider metadataProvider,
                ContractTypeSerializer serializer
                )
            {
                Register(async(QueueCommand q) => {
                    var queueSource = new TaskCompletionSource <QueueCommandResultType>();
                    var ctx         = new CommandPersisterContext(queueSource.Task);
                    var resultType  = QueueCommandResultType.Unknown;

                    try {
                        q.Context.Set(ctx, true);
                        QueueCommandResult result = await Next(q).Get();
                        resultType = result.Type;

                        if (result.Type == QueueCommandResultType.SuccessfullyQueued)
                        {
                            using (var scope = new TransactionScope(services, q.Context)) {
                                scope.Context.Set(new TimestampContext(DateTime.Now), true);
                                scope.Context.Set(new CommandContext(q.Command.ID), true);

                                QueueHelper h = new QueueHelper(
                                    serializer,
                                    repository: scope.GetRepository <ServerCommand>(),
                                    command: q.Command,
                                    metadata: metadataProvider.Provide(q.Context)
                                    );

                                if (await h.LoadExisting())
                                {
                                    if (!h.ExistingMatchesCurrent())
                                    {
                                        resultType = QueueCommandResultType.Rejected;
                                        return(QueueCommandResult.Rejected());
                                    }

                                    if (h.ExistingCompletedSuccessfully())
                                    {
                                        resultType = QueueCommandResultType.AlreadyExecuted;
                                        return(QueueCommandResult.AlreadyExecuted());
                                    }
                                }

                                ctx.Command = await h.CompleteQueue();
                                await scope.CommitAsync();
                            }
                        }

                        return(result);
                    } finally {
                        queueSource.SetResult(resultType);
                    }
                });

                Register(async(ExecuteCommand e) => {
                    var persisterCtx = e.Context.Get <CommandPersisterContext>();

                    if (await persisterCtx.QueueTask != QueueCommandResultType.SuccessfullyQueued)
                    {
                        return;
                    }

                    ServerCommand sc    = persisterCtx.Command.NotNull();
                    IServiceProvider sp = e.Context.Get <IServiceProvider>();

                    sc.BeginExecution(DateTime.Now);
                    await sp
                    .GetRepository <ServerCommand>()
                    .Save(sc);
                    await sp.GetRequiredService <ITransaction>().CommitAsync();

                    try {
                        await Next(e).Get();

                        // We have to use a new transaction here, because the oiginal one may time
                        // out if the execution of the command takes very long.
                        using (var scope = new TransactionScope(sp, e.Context)) {
                            sc.EndExecution(DateTime.Now);
                            await scope
                            .GetRepository <ServerCommand>()
                            .Save(sc);
                            await scope.CommitAsync();
                        }
                    } catch (Exception ex) when(!ex.IsCritical())
                    {
                        using (var scope = new TransactionScope(services, e.Context)) {
                            scope.Context.Set(new TimestampContext(DateTime.Now), true);
                            scope.Context.Set(new CommandContext(e.Command.ID), true);

                            sc.EndExecution(DateTime.Now, ex);
                            await scope
                            .GetRepository <ServerCommand>()
                            .Save(sc);

                            await scope.CommitAsync();
                        }

                        throw;
                    }
                });
            }