Example #1
0
 public CommandContext(
     string entityId,
     long sequence,
     string commandName,
     long commandId,
     AnySupport anySupport,
     IEventSourcedEntityHandler eventSourcedEntityHandler,
     int snapshotEvery,
     AbstractContext abstractContext,
     AbstractClientActionContext abstractClientActionContext,
     AbstractEffectContext abstractEffectContext,
     IActivatableContext activatableContext)
 {
     EntityId    = entityId;
     Sequence    = sequence;
     CommandName = commandName;
     CommandId   = commandId;
     AnySupport  = anySupport;
     EventSourcedEntityHandler   = eventSourcedEntityHandler;
     SnapshotEvery               = snapshotEvery;
     AbstractContext             = abstractContext;
     AbstractClientActionContext = abstractClientActionContext;
     AbstractEffectContext       = abstractEffectContext;
     ActivatableContext          = activatableContext;
 }
        private async Task HandleCommand(IEventSourcedStatefulService statefulService, MessageStreamingContext <EventSourcedStreamIn, EventSourcedStreamOut> stream,
                                         EventSourcedStreamIn message, string entityId, long sequence, IEventSourcedEntityHandler eventSourcedEntityHandler)
        {
            var command = message.Command;

            if (command.EntityId != entityId)
            {
                throw new InvalidOperationException("Entity received a message was not intended for itself");
            }
            var activatableContext = new AbstractActivatableContext();
            var commandContext     = new CommandContext(
                entityId,
                sequence,
                command.Name,
                command.Id,
                statefulService.AnySupport,
                eventSourcedEntityHandler,
                statefulService.SnapshotEvery,
                new AbstractContext(RootContext),
                new AbstractClientActionContext(command.Id, RootContext, activatableContext),
                new AbstractEffectContext(activatableContext),
                activatableContext
                );
            var reply = Optional.Option.None <Any>();

            try
            {
                // FIXME is this allowed to throw
                reply = eventSourcedEntityHandler.HandleCommand(command.Payload, commandContext);
            }
            catch (Exception ex)
            {
                switch (ex)
                {
                case FailInvokedException _:
                    reply = Optional.Option.Some(Any.Pack(new Empty()));
                    break;
                }
            }
            finally
            {
                activatableContext.Deactivate();
            }

            var anyResult = reply.ValueOr(() =>
                                          throw new InvalidOperationException("Command result was null"));
            var clientAction =
                commandContext.AbstractClientActionContext.CreateClientAction(reply, false);

            EventSourcedReply outReply;

            if (!commandContext.AbstractClientActionContext.HasError)
            {
                var endSequenceNumber = sequence + commandContext.Events.Count;
                var snapshot          = Optional.Option.None <Any>();
                if (commandContext.PerformSnapshot)
                {
                    var s = eventSourcedEntityHandler.Snapshot(
                        new SnapshotContext(
                            entityId,
                            endSequenceNumber,
                            RootContext.ServiceCallFactory
                            )
                        );
                    if (s.HasValue)
                    {
                        snapshot = s;
                    }
                }

                outReply = new EventSourcedReply
                {
                    CommandId    = message.Command.Id,
                    ClientAction = clientAction.ValueOr(() =>
                                                        throw new ArgumentNullException(nameof(clientAction)))
                };
                outReply.SideEffects.Add(commandContext.AbstractEffectContext.SideEffects);
                outReply.Events.Add(commandContext.Events); // UNSAFE
                snapshot.MatchSome(x => outReply.Snapshot = x);
            }
            else
            {
                outReply = new EventSourcedReply
                {
                    CommandId    = message.Command.Id,
                    ClientAction = new ClientAction
                    {
                        Reply = new Reply {
                            Payload = anyResult
                        }
                    }
                };
            }

            await stream.Response.WriteAsync(
                new EventSourcedStreamOut { Reply = outReply }
                );
        }