go_study/fabric-main/vendor/github.com/tedsuo/ifrit/grouper/client.go

154 lines
3.9 KiB
Go

package grouper
import (
"sync"
"github.com/tedsuo/ifrit"
)
/*
DynamicClient provides a client with group controls and event notifications.
A client can use the insert channel to add members to the group. When the group
becomes full, the insert channel blocks until a running process exits the group.
Once there are no more members to be added, the client can close the dynamic
group, preventing new members from being added.
*/
type DynamicClient interface {
/*
EntranceListener provides a new buffered channel of entrance events, which are
emited every time an inserted process is ready. To help prevent race conditions,
every new channel is populated with previously emited events, up to it's buffer
size.
*/
EntranceListener() <-chan EntranceEvent
/*
ExitListener provides a new buffered channel of exit events, which are emited
every time an inserted process exits. To help prevent race conditions, every
new channel is populated with previously emited events, up to it's buffer size.
*/
ExitListener() <-chan ExitEvent
/*
CloseNotifier provides a new unbuffered channel, which will emit a single event
once the group has been closed.
*/
CloseNotifier() <-chan struct{}
/*
Inserter provides an unbuffered channel for adding members to a group. When the
group becomes full, the insert channel blocks until a running process exits.
Once the group is closed, insert channels block forever.
*/
Inserter() chan<- Member
/*
Close causes a dynamic group to become a static group. This means that no new
members may be inserted, and the group will exit once all members have
completed.
*/
Close()
Get(name string) (ifrit.Process, bool)
}
type memberRequest struct {
Name string
Response chan ifrit.Process
}
/*
dynamicClient implements DynamicClient.
*/
type dynamicClient struct {
insertChannel chan Member
getMemberChannel chan memberRequest
completeNotifier chan struct{}
closeNotifier chan struct{}
closeOnce *sync.Once
entranceBroadcaster *entranceEventBroadcaster
exitBroadcaster *exitEventBroadcaster
}
func newClient(bufferSize int) dynamicClient {
return dynamicClient{
insertChannel: make(chan Member),
getMemberChannel: make(chan memberRequest),
completeNotifier: make(chan struct{}),
closeNotifier: make(chan struct{}),
closeOnce: new(sync.Once),
entranceBroadcaster: newEntranceEventBroadcaster(bufferSize),
exitBroadcaster: newExitEventBroadcaster(bufferSize),
}
}
func (c dynamicClient) Get(name string) (ifrit.Process, bool) {
req := memberRequest{
Name: name,
Response: make(chan ifrit.Process),
}
select {
case c.getMemberChannel <- req:
p, ok := <-req.Response
if !ok {
return nil, false
}
return p, true
case <-c.completeNotifier:
return nil, false
}
}
func (c dynamicClient) memberRequests() chan memberRequest {
return c.getMemberChannel
}
func (c dynamicClient) Inserter() chan<- Member {
return c.insertChannel
}
func (c dynamicClient) insertEventListener() <-chan Member {
return c.insertChannel
}
func (c dynamicClient) EntranceListener() <-chan EntranceEvent {
return c.entranceBroadcaster.Attach()
}
func (c dynamicClient) broadcastEntrance(event EntranceEvent) {
c.entranceBroadcaster.Broadcast(event)
}
func (c dynamicClient) closeEntranceBroadcaster() {
c.entranceBroadcaster.Close()
}
func (c dynamicClient) ExitListener() <-chan ExitEvent {
return c.exitBroadcaster.Attach()
}
func (c dynamicClient) broadcastExit(event ExitEvent) {
c.exitBroadcaster.Broadcast(event)
}
func (c dynamicClient) closeExitBroadcaster() {
c.exitBroadcaster.Close()
}
func (c dynamicClient) closeBroadcasters() error {
c.entranceBroadcaster.Close()
c.exitBroadcaster.Close()
close(c.completeNotifier)
return nil
}
func (c dynamicClient) Close() {
c.closeOnce.Do(func() {
close(c.closeNotifier)
})
}
func (c dynamicClient) CloseNotifier() <-chan struct{} {
return c.closeNotifier
}