@@ -3,7 +3,6 @@ package httpcluster
3
3
import (
4
4
"context"
5
5
"iter"
6
- "log/slog"
7
6
"maps"
8
7
9
8
"github.com/robbyt/go-supervisor/runnables/httpserver"
@@ -41,42 +40,42 @@ type entries struct {
41
40
servers map [string ]* serverEntry
42
41
}
43
42
44
- // newEntries creates a new entries collection from the previous state and desired configuration.
45
- // Each entry is marked with the action needed during the commit phase.
46
- func newEntries (
47
- previous * entries ,
48
- desiredConfigs map [string ]* httpserver.Config ,
49
- logger * slog.Logger ,
50
- ) * entries {
51
- logger = logger .WithGroup ("newEntries" )
43
+ // newEntries creates a new entries collection from desired configuration.
44
+ // This is used for initial creation only.
45
+ func newEntries (desiredConfigs map [string ]* httpserver.Config ) * entries {
52
46
servers := make (map [string ]* serverEntry )
53
47
54
- // Process existing servers (mark for stop, or update)
55
- if previous != nil {
56
- for id , oldEntry := range previous .servers {
57
- maps .Insert (servers , processExistingServer (id , oldEntry , desiredConfigs [id ], logger ))
58
- }
59
- }
60
-
61
- // Process new servers
62
48
for id , config := range desiredConfigs {
63
49
if config == nil {
64
50
continue
65
51
}
66
- if previous == nil || previous .servers [id ] == nil {
67
- // New server
68
- servers [id ] = & serverEntry {
69
- id : id ,
70
- config : config ,
71
- action : actionStart ,
72
- }
73
- logger .Debug ("New server marked for start" , "id" , id )
52
+ servers [id ] = & serverEntry {
53
+ id : id ,
54
+ config : config ,
55
+ action : actionStart ,
74
56
}
75
57
}
76
58
77
59
return & entries {servers : servers }
78
60
}
79
61
62
+ // removeEntry creates a new entries collection with the specified entry completely removed.
63
+ func (e * entries ) removeEntry (id string ) entriesManager {
64
+ _ , exists := e .servers [id ]
65
+ if ! exists {
66
+ return e
67
+ }
68
+
69
+ newServers := make (map [string ]* serverEntry , len (e .servers )- 1 )
70
+ for k , v := range e .servers {
71
+ if k != id {
72
+ newServers [k ] = v
73
+ }
74
+ }
75
+
76
+ return & entries {servers : newServers }
77
+ }
78
+
80
79
// getPendingActions returns lists of server IDs grouped by their pending action.
81
80
func (e * entries ) getPendingActions () (toStart , toStop []string ) {
82
81
for id , entry := range e .servers {
@@ -118,20 +117,18 @@ func (e *entries) commit() entriesManager {
118
117
servers := make (map [string ]* serverEntry )
119
118
120
119
for id , entry := range e .servers {
121
- switch entry .action {
122
- case actionStop :
120
+ if entry .action == actionStop {
123
121
// Don't copy stopped servers
124
122
continue
125
- default :
126
- // Copy entry with action cleared
127
- servers [id ] = & serverEntry {
128
- id : entry .id ,
129
- config : entry .config ,
130
- runner : entry .runner ,
131
- ctx : entry .ctx ,
132
- cancel : entry .cancel ,
133
- action : actionNone ,
134
- }
123
+ }
124
+ // Copy entry with action cleared
125
+ servers [id ] = & serverEntry {
126
+ id : entry .id ,
127
+ config : entry .config ,
128
+ runner : entry .runner ,
129
+ ctx : entry .ctx ,
130
+ cancel : entry .cancel ,
131
+ action : actionNone ,
135
132
}
136
133
}
137
134
@@ -209,11 +206,9 @@ func processExistingServer(
209
206
id string ,
210
207
oldEntry * serverEntry ,
211
208
desiredConfig * httpserver.Config ,
212
- logger * slog.Logger ,
213
209
) iter.Seq2 [string , * serverEntry ] {
214
210
return func (yield func (string , * serverEntry ) bool ) {
215
211
if oldEntry == nil {
216
- logger .Warn ("Old entry object is nil" , "id" , id )
217
212
return
218
213
}
219
214
@@ -222,7 +217,6 @@ func processExistingServer(
222
217
if oldEntry .runner != nil {
223
218
newEntry := * oldEntry
224
219
newEntry .action = actionStop
225
- logger .Debug ("Server marked for stop" , "id" , id )
226
220
yield (id , & newEntry )
227
221
}
228
222
// If runner is nil, server was never started, so skip it
@@ -233,7 +227,6 @@ func processExistingServer(
233
227
if oldEntry .config .Equal (desiredConfig ) {
234
228
newEntry := * oldEntry
235
229
newEntry .action = actionNone
236
- logger .Debug ("Server unchanged" , "id" , id )
237
230
yield (id , & newEntry )
238
231
return
239
232
}
@@ -254,17 +247,54 @@ func processExistingServer(
254
247
action : actionStart ,
255
248
}
256
249
257
- logger .Debug ("Server marked for restart" , "id" , id )
258
250
yield (id , startEntry )
259
251
return
260
252
}
261
253
262
254
// Not running, just start with new config
263
- logger .Debug ("Server marked for start" , "id" , id )
264
255
yield (id , & serverEntry {
265
256
id : id ,
266
257
config : desiredConfig ,
267
258
action : actionStart ,
268
259
})
269
260
}
270
261
}
262
+
263
+ // buildPendingEntries creates a new entries collection based on the desired state.
264
+ // It uses the current entries as the previous state and applies the same logic as newEntries.
265
+ func (e * entries ) buildPendingEntries (desired entriesManager ) entriesManager {
266
+ // Extract configs from the desired entries
267
+ desiredEntries , ok := desired .(* entries )
268
+ if ! ok {
269
+ return e
270
+ }
271
+
272
+ desiredConfigs := make (map [string ]* httpserver.Config )
273
+ for id , entry := range desiredEntries .servers {
274
+ desiredConfigs [id ] = entry .config
275
+ }
276
+
277
+ servers := make (map [string ]* serverEntry )
278
+
279
+ // Process existing servers (mark for stop, or update)
280
+ for id , oldEntry := range e .servers {
281
+ maps .Insert (servers , processExistingServer (id , oldEntry , desiredConfigs [id ]))
282
+ }
283
+
284
+ // Process new servers
285
+ for id , config := range desiredConfigs {
286
+ if config == nil {
287
+ continue
288
+ }
289
+ if e .servers [id ] == nil {
290
+ // New server
291
+ servers [id ] = & serverEntry {
292
+ id : id ,
293
+ config : config ,
294
+ action : actionStart ,
295
+ }
296
+ }
297
+ }
298
+
299
+ return & entries {servers : servers }
300
+ }
0 commit comments