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

Akka Fsm Update #2559

Merged
merged 4 commits into from
Mar 22, 2017
Merged

Akka Fsm Update #2559

merged 4 commits into from
Mar 22, 2017

Conversation

alexvaluyskiy
Copy link
Contributor

@alexvaluyskiy alexvaluyskiy commented Mar 16, 2017

/// <param name="nextStateName">State designator for the next state</param>
/// <param name="stateData">Data for next state</param>
/// <returns>State transition descriptor</returns>
[Obsolete("GoTo method is osboleted. Use GoTo(TState nextStateName) [1.2.0]")]
public State<TState, TData> GoTo(TState nextStateName, TData stateData)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This method is not present in the Scala API

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think I've even seen this method get used. It's always been GoTo().WithState AFAIK

@@ -1059,7 +1059,7 @@ public State ForMax(TimeSpan timeout)
/// <summary>
/// TBD
/// </summary>
public List<object> Replies
public IReadOnlyCollection<object> Replies
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should prefer ReadOnly* and Immutable collections in the public API. But this change could break compatibility

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It shouldn't really affect how end-users are consuming it that much, unless they were modifying the collection themselves which would have been "illegal" anyway. Guess this falls into the gray area of "is fixing a bug in the public API really a breaking change?" I'm fine with it.

[Fact]
public void FSM_must_notify_unhandled_messages()
{
// EventFilter
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

EventFilter chaining is not working as expected

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm assuming that's unrelated to this PR, and IIRC it's an area where we have some known bugs still anyway.

public class Shutdown : Reason { }
public sealed class Shutdown : Reason
{
private Shutdown() { }
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This one could break compatibility. Probably I should keep a public constructor with ObsoletedAttribute

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as previous. Go ahead and add that back.

public class Normal : Reason { }
public sealed class Normal : Reason
{
private Normal() { }
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This one could break compatibility. Probably I should keep a public constructor with ObsoletedAttribute

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I would do that.

if(_debugLog != null)
send = () =>
{
_debugLog.Debug("{0}Timer '{1}' went off. Sending {2} -> {3}",_ref.IsCancellationRequested ? "Cancelled " : "", name, message, actor);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why this debugging was implemented? It is not present in the scala API

}

/// <summary>
/// TBD
/// </summary>
public void Cancel()
{
if (!_ref.IsCancellationRequested)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IsCancellationRequested is always false

public class StateTimeout { }
public sealed class StateTimeout
{
private StateTimeout() { }
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This one could break compatibility. Probably I should keep a public constructor with ObsoletedAttribute

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as previous. Go ahead and add that back.

@alexvaluyskiy alexvaluyskiy changed the title [WIP] Akka Fsm Update Akka Fsm Update Mar 18, 2017
@alexvaluyskiy
Copy link
Contributor Author

Why we have implemented LoggingFsm and an interface with implicit behavior. Instead of creating LoggingFsm class?

@alexvaluyskiy
Copy link
Contributor Author

Should I implement this one?
akka/akka#17152

@alexvaluyskiy
Copy link
Contributor Author

When we are converting scala's traits, we should prefer to use Java API experience. Like to create an additional abstract class, like AbstractLoggingFSM

@alexvaluyskiy
Copy link
Contributor Author

alexvaluyskiy commented Mar 18, 2017

Why we need FSMBase abstract class? All messages should situated inside FSM class. FSMBase is redundant class. But we could not drop it without breaking changes.
At least we could make it static. And FSM actor will inherit ActorBase

Copy link
Member

@Aaronontheweb Aaronontheweb left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some minor changes requested, but otherwise it looks good.

@@ -768,52 +769,55 @@ namespace Akka.Actor
public abstract class FSMBase : Akka.Actor.ActorBase
{
protected FSMBase() { }
public class CurrentState<TS>
public sealed class CurrentState<TS>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sealing all of this off seems good to me.

@@ -846,14 +846,14 @@ namespace Akka.Persistence.Fsm
public void WhenUnhandled(Akka.Persistence.Fsm.PersistentFSMBase<TState, TData, TEvent>.StateFunction stateFunction) { }
public class State<TState, TData, TEvent> : Akka.Actor.FSMBase.State<TState, TData>
{
public State(TState stateName, TData stateData, System.Nullable<System.TimeSpan> timeout = null, Akka.Actor.FSMBase.Reason stopReason = null, System.Collections.Generic.List<object> replies = null, Akka.Util.ILinearSeq<TEvent> domainEvents = null, System.Action<TData> afterTransitionDo = null) { }
public State(TState stateName, TData stateData, System.Nullable<System.TimeSpan> timeout = null, Akka.Actor.FSMBase.Reason stopReason = null, System.Collections.Generic.IReadOnlyCollection<object> replies = null, Akka.Util.ILinearSeq<TEvent> domainEvents = null, System.Action<TData> afterTransitionDo = null) { }
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Like this change too. We should have been using read-only collections from the start here.

@@ -1059,7 +1059,7 @@ public State ForMax(TimeSpan timeout)
/// <summary>
/// TBD
/// </summary>
public List<object> Replies
public IReadOnlyCollection<object> Replies
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It shouldn't really affect how end-users are consuming it that much, unless they were modifying the collection themselves which would have been "illegal" anyway. Guess this falls into the gray area of "is fixing a bug in the public API really a breaking change?" I'm fine with it.

[Fact]
public void FSM_must_notify_unhandled_messages()
{
// EventFilter
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm assuming that's unrelated to this PR, and IIRC it's an area where we have some known bugs still anyway.

public class Normal : Reason { }
public sealed class Normal : Reason
{
private Normal() { }
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I would do that.

/// <param name="nextStateName">State designator for the next state</param>
/// <param name="stateData">Data for next state</param>
/// <returns>State transition descriptor</returns>
[Obsolete("GoTo method is osboleted. Use GoTo(TState nextStateName) [1.2.0]")]
public State<TState, TData> GoTo(TState nextStateName, TData stateData)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think I've even seen this method get used. It's always been GoTo().WithState AFAIK

if(_timers.ContainsKey(name))
if (DebugEvent)
{
_log.Debug($"setting {(repeat ? "repeating" : "")} timer {name}/{timeout}: {msg}");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Liking the C#6 API here... makes it way easier to read.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hold my beer. I'm planning to do C# 7 refactoring :)

_stateTimeouts.Add(state, timeout);
else
_stateTimeouts[state] = timeout;
_stateTimeouts.AddOrSet(state, timeout);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Change this to

stateTimeouts[state] = timeout

AddOrSet is something stupid I added to the codebase that we should deprecate and remove at some point. It's an unnecessary abstraction.

})
.With<InternalActivateFsmLogging>(_=> { DebugEvent = true; })
.Default(msg =>
ProcessMsg(StateTimeout.Instance, "state timeout");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Way easier to read (the main FSM handling routine) and will have fewer allocations also. Nice job.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should avoid of PatternMatch class

replies.Reverse();
foreach (var r in replies) { Sender.Tell(r); }
if (!_currentState.StateName.Equals(upcomingState.StateName))
nextState.Replies.Reverse().ForEach(r => Sender.Tell(r));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Much cleaner.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think I should get it back. List.Reverse has better performance than IEnumerable.Reverse

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

instead of reversing the list and then iterating, why not do both like

for (int i = nextState.Replies.Count - 1; i >= 0; i--)
{
    Sender.Tell(nextState.Replies[i]);
}

@alexvaluyskiy alexvaluyskiy force-pushed the updatefsm branch 3 times, most recently from 2159c5d to a2bd36f Compare March 22, 2017 06:58
@@ -854,7 +854,7 @@ namespace Akka.Persistence.Fsm
public System.Action<TData> AfterTransitionHandler { get; }
public Akka.Util.ILinearSeq<TEvent> DomainEvents { get; }
public bool Notifies { get; set; }
public System.Collections.Generic.IReadOnlyCollection<object> Replies { get; }
public System.Collections.Generic.IReadOnlyList<object> Replies { get; }
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why the switch to IReadOnlyList ?

Copy link
Contributor Author

@alexvaluyskiy alexvaluyskiy Mar 22, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because I've implemented this code :)

for (int i = nextState.Replies.Count - 1; i >= 0; i--)
{
    Sender.Tell(nextState.Replies[i]);
}

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

@Aaronontheweb
Copy link
Member

@alexvaluyskiy on the LoggingFsm bit, because I thought that preferable to having an explosion of base classes to choose from. Better to be able to decorate an existing one to add a piece of minor functionality like that instead of having to change the class you inherit from.

@Aaronontheweb Aaronontheweb merged commit 9f33872 into akkadotnet:dev Mar 22, 2017
@alexvaluyskiy alexvaluyskiy deleted the updatefsm branch March 22, 2017 19:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants