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