I. use scenarios
The background is to read oplog from kafka for incremental processing, but when I want to send a command to block the incremental process, and then start a full synchronization, I will continue incremental processing.
Therefore, multiple processes need to be controlled.
II. Use knowledge
1. Reading from an uninitialized pipeline will block
2. Reading from a closed pipe will not block
Control with two pipes and select
III. code above
Controller code
package util import ( "errors" "sync" ) const ( //STOP stop STOP = iota //START start START //PAUSE pause PAUSE ) //Control controller type Control struct { ch1 chan struct{} ch2 chan struct{} stat int64 lock sync.RWMutex } var ( //ErrStat error status ErrStat = errors.New("stat error") ) //NewControl gets a new Control func NewControl() *Control { return &Control{ ch1: make(chan struct{}), ch2: nil, stat: START, lock: sync.RWMutex{}, } } //Stop stop func (c *Control) Stop() error { c.lock.Lock() defer c.lock.Unlock() if c.stat == START { c.ch2 = nil close(c.ch1) c.stat = STOP } else if c.stat == PAUSE { ch2 := c.ch2 c.ch2 = nil close(c.ch1) close(ch2) c.stat = STOP } else { return ErrStat } return nil } //Pause pause func (c *Control) Pause() error { c.lock.Lock() defer c.lock.Unlock() if c.stat == START { c.ch2 = make(chan struct{}) close(c.ch1) c.stat = PAUSE } else { return ErrStat } return nil } //Start start func (c *Control) Start() error { c.lock.Lock() defer c.lock.Unlock() if c.stat == PAUSE { c.ch1 = make(chan struct{}) close(c.ch2) c.stat = START } else { return ErrStat } return nil } //C control pipe func (c *Control) C() <-chan struct{} { c.lock.RLock() defer c.lock.RUnlock() return c.ch1 } //Wait waiting func (c *Control) Wait() bool { c.lock.RLock() ch2 := c.ch2 c.lock.RUnlock() if ch2 == nil { //Send stop push command by assigning nil return false } <-ch2 //Will block return true }
Use code
for { select { case part, ok := <-c.Partitions(): if !ok { conf.Logger.Error("get kafka Partitions not ok", regular.Name) return } go readFromPart(c, part, regular, respChan) case <-regular.C(): //regular is a Control class if !regular.Wait() { conf.Logger.Debug("Stop! ") return } conf.Logger.Debug("Start! ") } }
In this way, you can control the cooperation in the project anytime and anywhere
regular := util.NewControl() regular.Pause() regular.Start() regular.Stop()