Example #1
0
                public async Task <ServerCommand> CompleteQueue()
                {
                    ServerCommand sc = _existing ?? new ServerCommand(_command.ID, _command.Target, _command.Message);

                    sc.Queued(DateTime.Now, _metadata);
                    await _repository.Save(sc);

                    return(sc);
                }
Example #2
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;
                    }
                });
            }