Skip to content

Commit

Permalink
Deadlock calling Event in after-event callback when current state == …
Browse files Browse the repository at this point in the history
…dst (#104)

* Deadlock in afterEventCallbacks in case when src == dst fixed

* Test added

---------

Co-authored-by: Igor Kuzmin <[email protected]>
  • Loading branch information
kuzmig and Igor Kuzmin authored Feb 13, 2024
1 parent e668a85 commit b2f0ab5
Show file tree
Hide file tree
Showing 2 changed files with 29 additions and 0 deletions.
4 changes: 4 additions & 0 deletions fsm.go
Original file line number Diff line number Diff line change
Expand Up @@ -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}
}
Expand Down
25 changes: 25 additions & 0 deletions fsm_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down

0 comments on commit b2f0ab5

Please sign in to comment.