diff --git a/fsm.go b/fsm.go index bd269d7..4465867 100644 --- a/fsm.go +++ b/fsm.go @@ -333,6 +333,10 @@ func (f *FSM) Event(ctx context.Context, event string, args ...interface{}) erro } if f.current == dst { + f.stateMu.RUnlock() + defer f.stateMu.RLock() + f.eventMu.Unlock() + unlocked = true f.afterEventCallbacks(ctx, e) return NoTransitionError{e.Err} } diff --git a/fsm_test.go b/fsm_test.go index 8e0c4ed..4d4479a 100644 --- a/fsm_test.go +++ b/fsm_test.go @@ -825,6 +825,31 @@ func TestNoTransition(t *testing.T) { } } +func TestNoTransitionAfterEventCallbackTransition(t *testing.T) { + var fsm *FSM + fsm = NewFSM( + "start", + Events{ + {Name: "run", Src: []string{"start"}, Dst: "start"}, + {Name: "finish", Src: []string{"start"}, Dst: "finished"}, + }, + Callbacks{ + "after_event": func(_ context.Context, e *Event) { + fsm.Event(context.Background(), "finish") + }, + }, + ) + err := fsm.Event(context.Background(), "run") + if _, ok := err.(NoTransitionError); !ok { + t.Error("expected 'NoTransitionError'") + } + + currentState := fsm.Current() + if currentState != "finished" { + t.Errorf("expected state to be 'finished', was '%s'", currentState) + } +} + func ExampleNewFSM() { fsm := NewFSM( "green",