-
Hi: |
Beta Was this translation helpful? Give feedback.
Replies: 5 comments 2 replies
-
Hello, thanks for the question. There was the same question a while ago #92 (comment) I would recommend to use this kind of supervisor in this way
so the code will be like: // definition
var (
numWorkers = 5
)
type control struct {
gen.Server
}
type controlState struct {
sup *supWorkers
supProcess gen.Process
workers []etf.Pid
counter uint64
}
type supWorkers struct {
gen.Supervisor
}
type worker struct {
gen.Server
}
/// callbacks for the 'control' process
func (c *control) Init(process *gen.ServerProcess, args ...etf.Term) error {
sup := &supWorkers{}
supOptions := gen.ProcessOptions{
Context: process.Context(), // inherited context to make sup process be hard linked with the control one
}
supProcess, err := process.Spawn("", supOptions, sup)
state := &controlState{
sup: sup,
supProcess: supProcess,
}
for i := 0; i < numWorkers; i++ { // start 5 worker processes
child, err := sup.StartChild(supProcess, "worker")
if err != nil {
return err
}
state.workers = append(state.workers, child.Self())
// monitor process in order to restart it on termination
process.MonitorProcess(child.Self())
}
process.State = state
return nil
}
func (c *control) HandleCast(process *gen.ServerProcess, message etf.Term) gen.ServerStatus {
state := process.State.(*controlState)
// use "round robin" to choose the worker process
n := int(state.counter % uint64(numWorkers))
state.counter++
// forward message
process.Cast(state.workers[n], message)
return gen.ServerStatusOK
}
func (c *control) HandleInfo(process *gen.ServerProcess, message etf.Term) gen.ServerStatus {
state := process.State.(*controlState)
switch m := message.(type) {
case gen.MessageDown:
for i, pid := range state.workers {
if pid != m.Pid {
continue
}
// restart terminated worker
child, err := state.sup.StartChild(state.supProcess, "worker")
if err != nil {
return err
}
process.MonitorProcess(child.Self())
state.workers[i] = child.Self()
break
}
default:
fmt.Printf("unknown request: %#v\n", m)
}
return gen.ServerStatusOK
}
// callback for the supervisor
func (s *supWorkers) Init(args ...etf.Term) (gen.SupervisorSpec, error) {
return gen.SupervisorSpec{
Name: "sup_workers",
Children: []gen.SupervisorChildSpec{
gen.SupervisorChildSpec{
Name: "worker",
Child: &worker{},
},
},
Strategy: gen.SupervisorStrategy{
Type: gen.SupervisorStrategySimpleOneForOne,
Intensity: 5,
Period: 5,
Restart: gen.SupervisorStrategyRestartTemporary,
},
}, nil
}
// callbacks for the 'worker' process
func (w *worker) Init(process *gen.ServerProcess, args ...etf.Term) error {
// do whatever you need for the initialization
return nil
}
func (w *worker) HandleCast(process *gen.ServerProcess, message etf.Term) gen.ServerStatus {
// handle cast message forwarded from the 'control' process
return gen.ServerStatusOK
} you may want to use |
Beta Was this translation helpful? Give feedback.
-
if you need to forward Call request you should:
type ForwardCall {
from gen.ServerFrom
message etf.Term
}
func (c *control) HandleCall(process *gen.ServerProcess, from gen.ServerFrom, message etf.Term) (etf.Term, gen.ServerStatus) {
state := process.State.(*controlState)
// use "round robin" to choose the worker process
n := int(state.counter % uint64(numWorkers))
state.counter++
// forward message
process.Send(state.workers[n], ForwardCall{from,message})
return nil, gen.ServerStatusIgnore
}
func (w *worker) HandleInfo(process *gen.ServerProcess, message etf.Term) gen.ServerStatus {
// handle call message forwarded from the 'control' process
switch m := message.(type) {
case ForwardCall:
// handle message
reply := "got it"
process.ReplyTo(m.from, reply)
}
return gen.ServerStatusOK
} |
Beta Was this translation helpful? Give feedback.
-
Thank you . |
Beta Was this translation helpful? Give feedback.
-
inspired by :) |
Beta Was this translation helpful? Give feedback.
-
@halturin how do you feel about making an Elixir inspired DynamicSupervisor to abstract much of the boilerplate away? |
Beta Was this translation helpful? Give feedback.
Hello, thanks for the question. There was the same question a while ago #92 (comment)
I would recommend to use this kind of supervisor in this way
so the code will be like: