@@ -107,6 +107,14 @@ type messageStartChild struct {
107
107
args []etf.Term
108
108
}
109
109
110
+ type messageStartChildBySpec struct {
111
+ childSpec SupervisorChildSpec
112
+ }
113
+
114
+ type messageStopChildByName struct {
115
+ processName string
116
+ }
117
+
110
118
// ProcessInit
111
119
func (sv * Supervisor ) ProcessInit (p Process , args ... etf.Term ) (ProcessState , error ) {
112
120
behavior , ok := p .Behavior ().(SupervisorBehavior )
@@ -182,6 +190,45 @@ func (sv *Supervisor) StartChild(supervisor Process, name string, args ...etf.Te
182
190
return process , nil
183
191
}
184
192
193
+ // StartChildBySpec dynamically adds child spec and starts a child process with given spec which is undefined by Init call.
194
+ // not surport simple_one_for_one strategy type.
195
+ // Similar to erlang[supervisor:start_child/2].
196
+ func StartChildBySpec (supervisor Process , spec SupervisorChildSpec ) (Process , error ) {
197
+ if spec .state != supervisorChildStateStart {
198
+ return nil , fmt .Errorf ("spec state is invalid %#v" , spec .state )
199
+ }
200
+ message := messageStartChildBySpec {
201
+ childSpec : spec ,
202
+ }
203
+ value , err := supervisor .Direct (message )
204
+ if err != nil {
205
+ return nil , err
206
+ }
207
+ process , ok := value .(Process )
208
+ if ! ok {
209
+ return nil , fmt .Errorf ("internal error: can't start child %#v" , value )
210
+ }
211
+ return process , nil
212
+ }
213
+
214
+ // StopChildByName dynamically deletes child spec and stop a child process with given process name.
215
+ // not surport simple_one_for_one strategy type.
216
+ // Similar to erlang[supervisor:terminate_child(Sup, ID), supervisor:delete_child(Sup, ID)].
217
+ func StopChildByName (supervisor Process , processName string ) (SupervisorChildSpec , error ) {
218
+ message := messageStopChildByName {
219
+ processName : processName ,
220
+ }
221
+ value , err := supervisor .Direct (message )
222
+ if err != nil {
223
+ return SupervisorChildSpec {}, err
224
+ }
225
+ childSpec , ok := value .(SupervisorChildSpec )
226
+ if ! ok {
227
+ return SupervisorChildSpec {}, fmt .Errorf ("internal error:%#v" , value )
228
+ }
229
+ return childSpec , nil
230
+ }
231
+
185
232
func startChildren (supervisor Process , spec * SupervisorSpec ) {
186
233
spec .restarts = append (spec .restarts , time .Now ().Unix ())
187
234
if len (spec .restarts ) > int (spec .Strategy .Intensity ) {
@@ -261,6 +308,42 @@ func handleDirect(supervisor Process, spec *SupervisorSpec, message interface{})
261
308
spec .Children = append (spec .Children , childSpec )
262
309
return process , nil
263
310
311
+ case messageStartChildBySpec :
312
+ if spec .Strategy .Type == SupervisorStrategySimpleOneForOne {
313
+ return nil , fmt .Errorf ("startSpecChild not surport simple_one_for_one" )
314
+ }
315
+ childSpec := m .childSpec
316
+ _ , err := lookupSpecByName (childSpec .Name , spec .Children )
317
+ if err == nil {
318
+ return nil , fmt .Errorf ("%s specChild is exist" , childSpec .Name )
319
+ }
320
+ childSpec .state = supervisorChildStateRunning
321
+ process := startChild (supervisor , childSpec .Name , childSpec .Child , childSpec .Options , childSpec .Args ... )
322
+ childSpec .process = process
323
+ spec .Children = append (spec .Children , childSpec )
324
+ return process , nil
325
+
326
+ case messageStopChildByName :
327
+ if spec .Strategy .Type == SupervisorStrategySimpleOneForOne {
328
+ return nil , fmt .Errorf ("startSpecChild not surport simple_one_for_one" )
329
+ }
330
+ processName := m .processName
331
+ childSpec , err := lookupSpecByName (processName , spec .Children )
332
+ if err != nil {
333
+ return nil , err
334
+ }
335
+ childProc := childSpec .process
336
+ if childSpec .state != supervisorChildStateRunning && childProc != nil {
337
+ return nil , fmt .Errorf ("childSpec:%v can not stop" , childSpec )
338
+ }
339
+ //delete spec
340
+ supervisor .Unlink (childProc .Self ())
341
+ spec .Children = deleteSpecByName (processName , spec .Children )
342
+ //terminate child
343
+ //Similar to erlang[supervisor:shutdown/1](exit(Pid, shutdown)).
344
+ childProc .Exit ("shutdown" )
345
+ return childSpec , nil
346
+
264
347
default :
265
348
}
266
349
@@ -446,3 +529,13 @@ func lookupSpecByName(specName string, spec []SupervisorChildSpec) (SupervisorCh
446
529
}
447
530
return SupervisorChildSpec {}, fmt .Errorf ("unknown child" )
448
531
}
532
+
533
+ func deleteSpecByName (specName string , spec []SupervisorChildSpec ) []SupervisorChildSpec {
534
+ ret := make ([]SupervisorChildSpec , 0 , len (spec ))
535
+ for i := range spec {
536
+ if spec [i ].Name != specName {
537
+ ret = append (ret , spec [i ])
538
+ }
539
+ }
540
+ return ret
541
+ }
0 commit comments