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
Incorrect transition between nested states #421
Comments
@aleneum Can you please take a look? |
I am not sure whether this is still relevant for you. I guess you refer to |
That's exactly the problem. Instead, we transition to Could this be related to #419? |
Oh, I see. Did you await the event triggers or did you run them in the asyncio loop: m = Service()
m.add_transition('travel', ServiceState.initialized, ServiceState.stopped)
asyncio.run(m.travel())
asyncio.run(m.stopped()) If so, then this problem might be indeed solved by #419. |
I |
Does it work for you now with the latest version from |
Unfortunately, there's another bug and this is not related to #419.
|
I am not sure if I get this test right but dont you always add a transition named 'travel' and then call it? Why should that fail? Edit: Oh! Sorry, I missed the second part! My bad. |
You defined transitions = [
['starting', [ServiceState.initialized, ServiceState.stopped], ServiceState.starting],
['started', [ServiceState.starting, ServiceRestartState.starting], ServiceState.started],
['restarting', ServiceState.started, ServiceState.restarting],
# ['stopping', ServiceState.restarting, ServiceRestartState.stopping],
['stopped', ServiceRestartState.stopping, ServiceRestartState.stopped],
['starting', ServiceRestartState.stopped, ServiceRestartState.starting],
['stopping', ServiceState.started, ServiceState.stopping],
['stopped', ServiceState.stopping, ServiceState.stopped],
] ... you will get a Design-wise you could add an 'initial' state to class ServiceRestartState(Enum):
pending = auto()
starting = auto()
stopping = auto()
stopped = auto()
# ...
transitions = [
['starting', [ServiceState.initialized, ServiceState.stopped], ServiceState.starting],
['started', [ServiceState.starting, ServiceRestartState.starting], ServiceState.started],
['restarting', ServiceState.started, ServiceRestartState.pending],
['stopping', ServiceRestartState.pending, ServiceRestartState.stopping],
['stopped', ServiceRestartState.stopping, ServiceRestartState.stopped],
['starting', ServiceRestartState.stopped, ServiceRestartState.starting],
['stopping', ServiceState.started, ServiceState.stopping],
['stopped', ServiceState.stopping, ServiceState.stopped],
] |
I created a custom state because of #427 which is now fixed. |
Maybe I'm just too tired, but I've been staring at this for a couple of days and I can't figure out what you're saying and why I'd need another state. Can you rephrase that? |
Sure, first a quote from the SCXML documentation that describes this behaviour:
An event definition like s.restarting()
# INFO:transitions.core:Entered state restarting
s.stopping()
# INFO:transitions.core:Entered state restarting_stopping
s.stopped()
# INFO:transitions.core:Exited state restarting_stopping
# INFO:transitions.core:Entered state restarting_stopped
s.stopping()
# !restarting_stopped should be exited here! <-- this is a bug [fixed!]
# INFO:transitions.core:Entered state restarting_stopping If I get you right, you don't want 'stopping' to be a valid event in |
Maybe its easier to see when using transitions-gui since references FROM parent states to child states arent depicted nicely in graphviz (self-references to compound states are even worse). |
|
Yes exactly. |
You could use conditions and allow transitions only from the parent state itself: class Service(HierarchicalMachine):
def __init__(self):
transitions = [
['starting', [ServiceState.initialized, ServiceState.stopped], ServiceState.starting],
['started', [ServiceState.starting, ServiceRestartState.starting], ServiceState.started],
['restarting', ServiceState.started, ServiceState.restarting],
dict(trigger='stopping', source=ServiceState.restarting, dest=ServiceRestartState.stopping, conditions='is_restarting'),
['stopped', ServiceRestartState.stopping, ServiceRestartState.stopped],
['starting', ServiceRestartState.stopped, ServiceRestartState.starting],
['stopping', ServiceState.started, ServiceState.stopping],
['stopped', ServiceState.stopping, ServiceState.stopped],
]
super().__init__(states=ServiceState,
transitions=transitions,
initial=ServiceState.initialized,
auto_transitions=False)
logging.basicConfig(level=logging.INFO)
s = Service()
s.starting()
s.started()
s.restarting()
s.stopping()
s.stopped()
assert not s.stopping() # will return False since it does not fulfill condition 'is_restarting'
assert s.is_restarting_stopped() |
I'll try that. |
Consider the following state machine:
If I am currently at the stopped stage I can't transition to stopped.
However if you do attempt to do so the
stopped
trigger will transition the state machine toServiceRestartState.stopped
.Try the code below:
I tried changing the name of the nested states, I tried to rename the triggers to not be the same. Nothing works.
The text was updated successfully, but these errors were encountered: