@@ -20,7 +20,6 @@ import (
20
20
"errors"
21
21
"fmt"
22
22
"log/slog"
23
- "time"
24
23
)
25
24
26
25
type (
@@ -95,26 +94,38 @@ func (fsm *FSM) Handle(handler Handler) {
95
94
// Write a Command to the FSM. This Command will be encoded using the Encoding implementation and stored within the
96
95
// database, where it can then be read and the relevant Handler invoked.
97
96
func (fsm * FSM ) Write (ctx context.Context , cmd Command ) error {
98
- fsm .options .logger .
99
- With (slog .String ("command_kind" , cmd .Kind ())).
100
- InfoContext (ctx , "writing command" )
101
-
102
97
return transaction (ctx , fsm .db , func (ctx context.Context , tx * sql.Tx ) error {
103
- return insert (ctx , tx , fsm .options .encoder , cmd )
98
+ switch command := cmd .(type ) {
99
+ case batchCommand :
100
+ for _ , cmd = range command {
101
+ fsm .options .logger .
102
+ With (slog .String ("command_kind" , cmd .Kind ())).
103
+ InfoContext (ctx , "writing command" )
104
+
105
+ if err := insert (ctx , tx , fsm .options .encoder , cmd ); err != nil {
106
+ return err
107
+ }
108
+ }
109
+ default :
110
+ fsm .options .logger .
111
+ With (slog .String ("command_kind" , cmd .Kind ())).
112
+ InfoContext (ctx , "writing command" )
113
+
114
+ return insert (ctx , tx , fsm .options .encoder , cmd )
115
+ }
116
+
117
+ return nil
104
118
})
105
119
}
106
120
107
121
// Read commands from the FSM. For each command read, the relevant Handler implementation will be invoked. This method
108
122
// blocks until the provided context is cancelled, or a Handler implementation returns an error.
109
123
func (fsm * FSM ) Read (ctx context.Context ) error {
110
- ticker := time .NewTicker (time .Second / 10 )
111
- defer ticker .Stop ()
112
-
113
124
for {
114
125
select {
115
126
case <- ctx .Done ():
116
127
return ctx .Err ()
117
- case <- ticker . C :
128
+ default :
118
129
if err := fsm .next (ctx ); err != nil {
119
130
return err
120
131
}
@@ -154,10 +165,26 @@ func (fsm *FSM) next(ctx context.Context) error {
154
165
}
155
166
156
167
if cmd != nil {
157
- log .With (slog .String ("received_command_kind" , cmd .Kind ())).
158
- InfoContext (ctx , "received additional command" )
159
168
160
- if err = insert (ctx , tx , fsm .options .encoder , cmd ); err != nil {
169
+ switch command := cmd .(type ) {
170
+ case batchCommand :
171
+ for _ , cmd = range command {
172
+ log .With (slog .String ("received_command_kind" , cmd .Kind ())).
173
+ InfoContext (ctx , "received additional command" )
174
+
175
+ if err = insert (ctx , tx , fsm .options .encoder , cmd ); err != nil {
176
+ return err
177
+ }
178
+ }
179
+
180
+ default :
181
+ log .With (slog .String ("received_command_kind" , cmd .Kind ())).
182
+ InfoContext (ctx , "received additional command" )
183
+
184
+ err = insert (ctx , tx , fsm .options .encoder , cmd )
185
+ }
186
+
187
+ if err != nil {
161
188
return err
162
189
}
163
190
}
@@ -249,3 +276,18 @@ func UseEncoding(e Encoding) Option {
249
276
func UseLogger (l * slog.Logger ) Option {
250
277
return func (o * options ) { o .logger = l .WithGroup ("pgfsm" ) }
251
278
}
279
+
280
+ type (
281
+ batchCommand []Command
282
+ )
283
+
284
+ func (cmd batchCommand ) Kind () string {
285
+ return ""
286
+ }
287
+
288
+ // Batch returns a single Command implementation that wraps multiple other Command implementations. This can be used
289
+ // to return multiple commands at once when returning from a CommandHandler function. Or to send multiple commands to
290
+ // the FSM at once using FSM.Write.
291
+ func Batch (commands ... Command ) Command {
292
+ return batchCommand (commands )
293
+ }
0 commit comments