Skip to content

Commit e71990f

Browse files
committed
upgrade go-fsm to v2
1 parent 4a0c1d6 commit e71990f

File tree

4 files changed

+106
-33
lines changed

4 files changed

+106
-33
lines changed

go.mod

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,15 @@ module github.com/robbyt/go-supervisor
33
go 1.25.3
44

55
require (
6-
github.com/robbyt/go-fsm v1.5.0
6+
github.com/robbyt/go-fsm/v2 v2.0.0-20250101000000-a34867a27ffa
77
github.com/stretchr/testify v1.11.1
88
)
99

1010
require (
1111
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
1212
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
13-
github.com/stretchr/objx v0.5.2 // indirect
13+
github.com/stretchr/objx v0.5.3 // indirect
1414
gopkg.in/yaml.v3 v3.0.1 // indirect
1515
)
16+
17+
replace github.com/robbyt/go-fsm/v2 => /Users/rterhaar/code/golang/go-fsm

go.sum

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,8 @@ github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1
22
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
33
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
44
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
5-
github.com/robbyt/go-fsm v1.5.0 h1:yz+6sQ73ODkL8zWOh3I7kegoSJoGwLL8nTn47ggPikc=
6-
github.com/robbyt/go-fsm v1.5.0/go.mod h1:yvh/ZRAvdzLz9Y3UB9Zz3YbnAumn4nI2P5xvaC6e3II=
7-
github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY=
8-
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
5+
github.com/stretchr/objx v0.5.3 h1:jmXUvGomnU1o3W/V5h2VEradbpJDwGrzugQQvL0POH4=
6+
github.com/stretchr/objx v0.5.3/go.mod h1:rDQraq+vQZU7Fde9LOZLr8Tax6zZvy4kuNKF+QYS+U0=
97
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
108
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
119
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=

internal/finitestate/machine.go

Lines changed: 89 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -5,39 +5,113 @@ import (
55
"log/slog"
66
"time"
77

8-
"github.com/robbyt/go-fsm"
8+
"github.com/robbyt/go-fsm/v2"
9+
"github.com/robbyt/go-fsm/v2/hooks"
10+
"github.com/robbyt/go-fsm/v2/hooks/broadcast"
11+
"github.com/robbyt/go-fsm/v2/transitions"
912
)
1013

1114
const (
12-
StatusNew = fsm.StatusNew
13-
StatusBooting = fsm.StatusBooting
14-
StatusRunning = fsm.StatusRunning
15-
StatusReloading = fsm.StatusReloading
16-
StatusStopping = fsm.StatusStopping
17-
StatusStopped = fsm.StatusStopped
18-
StatusError = fsm.StatusError
19-
StatusUnknown = fsm.StatusUnknown
15+
StatusNew = transitions.StatusNew
16+
StatusBooting = transitions.StatusBooting
17+
StatusRunning = transitions.StatusRunning
18+
StatusReloading = transitions.StatusReloading
19+
StatusStopping = transitions.StatusStopping
20+
StatusStopped = transitions.StatusStopped
21+
StatusError = transitions.StatusError
22+
StatusUnknown = transitions.StatusUnknown
2023
)
2124

2225
// TypicalTransitions is a set of standard transitions for a finite state machine.
23-
var TypicalTransitions = fsm.TypicalTransitions
26+
var TypicalTransitions = transitions.Typical
2427

25-
// Machine is a wrapper around go-fsm.Machine that provides additional functionality.
28+
// Machine is a wrapper around go-fsm v2 that provides the v1 API compatibility.
29+
// It manages both the FSM and broadcast functionality.
2630
type Machine struct {
2731
*fsm.Machine
32+
broadcastManager *broadcast.Manager
2833
}
2934

30-
// GetStateChan returns a channel that emits the state whenever it changes.
35+
// GetStateChanWithTimeout returns a channel that emits the state whenever it changes.
3136
// The channel is closed when the provided context is canceled.
37+
// For v1 API compatibility, the current state is sent immediately to the channel.
3238
func (s *Machine) GetStateChanWithTimeout(ctx context.Context) <-chan string {
33-
return s.GetStateChanWithOptions(ctx, fsm.WithSyncTimeout(5*time.Second))
39+
return s.getStateChanInternal(ctx, broadcast.WithTimeout(5*time.Second))
40+
}
41+
42+
// GetStateChan returns a channel that emits the state whenever it changes.
43+
// The channel is closed when the provided context is canceled.
44+
// For v1 API compatibility, the current state is sent immediately to the channel.
45+
func (s *Machine) GetStateChan(ctx context.Context) <-chan string {
46+
return s.getStateChanInternal(ctx)
47+
}
48+
49+
// GetStateChanWithOptions returns a channel that emits the state whenever it changes
50+
// with custom broadcast options.
51+
// For v1 API compatibility, the current state is sent immediately to the channel.
52+
func (s *Machine) GetStateChanWithOptions(ctx context.Context, opts ...broadcast.Option) <-chan string {
53+
return s.getStateChanInternal(ctx, opts...)
54+
}
55+
56+
// getStateChanInternal is a helper that creates a channel and sends the current state to it.
57+
// This maintains v1 API compatibility where GetStateChan immediately sends the current state.
58+
func (s *Machine) getStateChanInternal(ctx context.Context, opts ...broadcast.Option) <-chan string {
59+
wrappedCh := make(chan string, 1)
60+
61+
userCh, err := s.broadcastManager.GetStateChan(ctx, opts...)
62+
if err != nil {
63+
close(wrappedCh)
64+
return wrappedCh
65+
}
66+
67+
currentState := s.GetState()
68+
wrappedCh <- currentState
69+
70+
go func() {
71+
defer close(wrappedCh)
72+
for state := range userCh {
73+
wrappedCh <- state
74+
}
75+
}()
76+
77+
return wrappedCh
3478
}
3579

3680
// New creates a new finite state machine with the specified logger using "standard" state transitions.
81+
// This function provides compatibility with the v1 API while using v2 under the hood.
3782
func New(handler slog.Handler) (*Machine, error) {
38-
f, err := fsm.New(handler, StatusNew, TypicalTransitions)
83+
registry, err := hooks.NewRegistry(
84+
hooks.WithLogHandler(handler),
85+
hooks.WithTransitions(TypicalTransitions),
86+
)
87+
if err != nil {
88+
return nil, err
89+
}
90+
91+
broadcastManager := broadcast.NewManager(handler)
92+
93+
err = registry.RegisterPostTransitionHook(hooks.PostTransitionHookConfig{
94+
Name: "broadcast",
95+
From: []string{"*"},
96+
To: []string{"*"},
97+
Action: broadcastManager.BroadcastHook,
98+
})
99+
if err != nil {
100+
return nil, err
101+
}
102+
103+
f, err := fsm.New(
104+
StatusNew,
105+
TypicalTransitions,
106+
fsm.WithLogHandler(handler),
107+
fsm.WithCallbackRegistry(registry),
108+
)
39109
if err != nil {
40110
return nil, err
41111
}
42-
return &Machine{Machine: f}, nil
112+
113+
return &Machine{
114+
Machine: f,
115+
broadcastManager: broadcastManager,
116+
}, nil
43117
}

internal/finitestate/machine_test.go

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ import (
77
"testing"
88
"time"
99

10-
"github.com/robbyt/go-fsm"
1110
"github.com/stretchr/testify/assert"
1211
"github.com/stretchr/testify/require"
1312
)
@@ -183,19 +182,19 @@ func TestMachineInterface(t *testing.T) {
183182
func TestTypicalTransitions(t *testing.T) {
184183
t.Parallel()
185184

186-
t.Run("verify TypicalTransitions matches fsm package", func(t *testing.T) {
187-
assert.Equal(t, fsm.TypicalTransitions, TypicalTransitions)
185+
t.Run("verify TypicalTransitions is not nil", func(t *testing.T) {
186+
assert.NotNil(t, TypicalTransitions)
188187
})
189188

190-
t.Run("verify status constants match fsm package", func(t *testing.T) {
191-
assert.Equal(t, fsm.StatusNew, StatusNew)
192-
assert.Equal(t, fsm.StatusBooting, StatusBooting)
193-
assert.Equal(t, fsm.StatusRunning, StatusRunning)
194-
assert.Equal(t, fsm.StatusReloading, StatusReloading)
195-
assert.Equal(t, fsm.StatusStopping, StatusStopping)
196-
assert.Equal(t, fsm.StatusStopped, StatusStopped)
197-
assert.Equal(t, fsm.StatusError, StatusError)
198-
assert.Equal(t, fsm.StatusUnknown, StatusUnknown)
189+
t.Run("verify status constants are defined", func(t *testing.T) {
190+
assert.Equal(t, "New", StatusNew)
191+
assert.Equal(t, "Booting", StatusBooting)
192+
assert.Equal(t, "Running", StatusRunning)
193+
assert.Equal(t, "Reloading", StatusReloading)
194+
assert.Equal(t, "Stopping", StatusStopping)
195+
assert.Equal(t, "Stopped", StatusStopped)
196+
assert.Equal(t, "Error", StatusError)
197+
assert.Equal(t, "Unknown", StatusUnknown)
199198
})
200199
}
201200

0 commit comments

Comments
 (0)