Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PersistentFSM: Data passed to AndThen is not the latest version #3654

Closed
aloker opened this issue Nov 18, 2018 · 0 comments
Closed

PersistentFSM: Data passed to AndThen is not the latest version #3654

aloker opened this issue Nov 18, 2018 · 0 comments

Comments

@aloker
Copy link
Contributor

aloker commented Nov 18, 2018

Akka version: 1.3.10
Platform : .NET Core 2.1/Windows

When defining a side effect in PersistentFSM, the data object passed to the AndThen callback is NOT the version returned from ApplyEvent.

Consider this actor. When it receives a Command, it updates the state data (Data) by applying the CommandReceived event and uses the AndThen function to reply the current Data to the sender.

public class AndThenTestActor : PersistentFSM<AndThenTestActor.IState, AndThenTestActor.Data, AndThenTestActor.IEvent>
{
    public override string PersistenceId => "PersistentFSMSpec.AndThenTestActor";

    public AndThenTestActor()
    {
        StartWith(Init.Instance, new Data());
        When(Init.Instance, (evt, state) =>
        {
            switch (evt.FsmEvent)
            {
                case Command cmd:
                    return Stay()
                        .Applying(new CommandReceived(cmd.Value))
                        .AndThen(data =>
                        {
                            // NOTE At this point, I'd expect data to be the value returned by ApplyEvent
                            Sender.Tell(data, Self);
                        });
                default:
                    return Stay();
            }
        });
    }

    protected override Data ApplyEvent(IEvent domainEvent, Data currentData)
    {
        switch (domainEvent)
        {
            case CommandReceived cmd:
                // Data is immutable; a new object with the applied event is returned
                return new Data(cmd.Value);
            default:
                return currentData;
        }
    }


    public interface IState : PersistentFSM.IFsmState
    {
    }

    public class Init : IState
    {
        public static readonly Init Instance = new Init();
        public string Identifier => "Init";
    }

    public class Data
    {
        public Data()
        {
        }

        public Data(string value)
        {
            Value = value;
        }

        public string Value { get; }
    }

    public interface IEvent
    {
    }

    public class CommandReceived : IEvent
    {
        public CommandReceived(string value)
        {
            Value = value;
        }

        public string Value { get; }
    }

    public class Command
    {
        public Command(string value)
        {
            Value = value;
        }

        public string Value { get; }
    }
}

Let's say I ask the actor like so, I'd expect the returned data to reflect the latest changes.

var response = await actor.Ask<AndThenTestActor.Data>(new AndThenTestActor.Command("test"));
Assert.Equal("test", response.Value);

However, it does not! Instead I get the Data object that was the state data before applying the event.

The reason can be found here:

base.ApplyState(nextState.Using(nextData));
CurrentStateTimeout = nextState.Timeout;
nextState.AfterTransitionDo?.Invoke(nextState.StateData);

nextState.Using(nextData) creates a copy of the state with the new data applied, however, the nextState used to access StateData in nextState.AfterTransitionDo?.Invoke(nextState.StateData); is the old state, before the copy.

I've created fix + tests in a separate pull request.

@Aaronontheweb Aaronontheweb added this to the 1.4.0 milestone Jul 8, 2019
Aaronontheweb pushed a commit that referenced this issue Oct 4, 2019
…on (#3654) (#3948)

Fixes issue #3654 in conformance with the JVM version of PersistentFSM.
Aaronontheweb pushed a commit to Aaronontheweb/akka.net that referenced this issue Nov 14, 2019
…on (akkadotnet#3654) (akkadotnet#3948)

Fixes issue akkadotnet#3654 in conformance with the JVM version of PersistentFSM.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants