ETLCPP / etl

Embedded Template Library
https://www.etlcpp.com
MIT License
2.05k stars 372 forks source link

HFSM state changed with error state #813

Closed CodingPapi closed 5 months ago

CodingPapi commented 5 months ago

Hi I have used hfsm with message bus, I will wirte some bref introduction about my current situations:

I have BootingState and ReadyState in hfsm state list, and in booting state, it published a msg to other place and will be immediately replyed with a new msg that will trigger BootingState to ReadyState in hfsm. The issuse is when I replyed immediately, the hfsm state will change, on_enter callback of ReadyState will be called, but hfsm.receive() method still pass event to BootingState class. But when I reply msgB with some delay, everyting is ok now. hfsm.receive() will pass events to new Ready state.

what happens here? what wrong with my usage of hfsm and message bus?

thank you for your time. thanks in advance

BootingState::on_enter_state() { // publish a message to message bus msgDispatcher.receive(msgA); return No_State_Change; }

MSGRouterA::on_receive(xxx msgA) { // immediately publish another msg to switch to another State // if I dispatch msgB immediately, it will cause issues. // if I delay some time here, then dispatch msgB, everything goes fine msgDispatcher.receive(msgB) }

BootingState::on_event(msgB) { // msgB is forwarded into hfsm by router return StateId::ReadyState; }

CodingPapi commented 5 months ago

if I directly return a ReadyState id in booting on_enter_state callback, it will still be BootingState, Is this normal?

BootingState::on_enter_state() { return StateId::ReadyState; // on_enter_state callback of ReadyState will not be called }

jwellbelove commented 5 months ago

_if I directly return a ReadyState id in booting on_enterstate callback, it will still be BootingState, Is this normal?

Yes, see https://www.etlcpp.com/hfsm.html

jwellbelove commented 5 months ago

Not returning ifsm_state::No_State_Change from on_enter_state should raise a etl::fsm_state_composite_state_change_forbidden assert.

jwellbelove commented 5 months ago

The message based state machines do not support recursive message dispatch.

CodingPapi commented 5 months ago

The message based state machines do not support recursive message dispatch.

Hi jwellbelove, what do you mean recursive dispatch?Dispatch another msg in an on_receive callback? I use msgA to trigger msgB, msgB dispatched in routers on_receive callback, and hfsm use msgB to change state, is this not supported?

jwellbelove commented 5 months ago

I mean that the ETL's FSM & HFSM were not designed to allow processing of new events whilst in the middle of processing the current event. You need to allow each event to complete before receive is called again.

CodingPapi commented 5 months ago

I am clear now, thank you very much for your quick response. This is relally a great project

CodingPapi commented 5 months ago

I mean that the ETL's FSM & HFSM were not designed to allow processing of new events whilst in the middle of processing the current event. You need to allow each event to complete before receive is called again.

aha, I have another question, how do I know the current event is done? after it return the new State ID or return no state change from the on_event method?

CodingPapi commented 5 months ago

I mean that the ETL's FSM & HFSM were not designed to allow processing of new events whilst in the middle of processing the current event. You need to allow each event to complete before receive is called again.

aha, I have another question, how do I know the current event is done? after it return the new State ID or return no state change from the on_event method?

you mean I should not trigger a new msg inside on_receive?

jwellbelove commented 5 months ago

The event handling is complete on return from the FSM's receive(const etl::imessage& message).

you mean I should not trigger a new msg inside on_receive?

That is correct. You must buffer the new message so that it may be sent to receive(const etl::imessage& message) after the previous message has completed.

CodingPapi commented 5 months ago

lets say if we use Lock, we should lock before receive, and unlock after receive returns