Improve docker events handling: separate channel for status updates

Instead of calling a heavy inspect api call we can easily changing status just by knowing an action.
Let's do this in a separate channel decouple UI update from basic event loop.
This commit is contained in:
Sergey Ponomarev
2020-11-17 22:00:03 +02:00
parent b65e970a83
commit 4c280cee56

View File

@@ -23,10 +23,17 @@ var actionToStatus = map[string]string{
"unpause": "running", "unpause": "running",
} }
type StatusUpdate struct {
Cid string
Field string // "status" or "health"
Status string
}
type Docker struct { type Docker struct {
client *api.Client client *api.Client
containers map[string]*container.Container containers map[string]*container.Container
needsRefresh chan string // container IDs requiring refresh needsRefresh chan string // container IDs requiring refresh
statuses chan StatusUpdate
closed chan struct{} closed chan struct{}
lock sync.RWMutex lock sync.RWMutex
} }
@@ -41,6 +48,7 @@ func NewDocker() (Connector, error) {
client: client, client: client,
containers: make(map[string]*container.Container), containers: make(map[string]*container.Container),
needsRefresh: make(chan string, 60), needsRefresh: make(chan string, 60),
statuses: make(chan StatusUpdate, 60),
closed: make(chan struct{}), closed: make(chan struct{}),
lock: sync.RWMutex{}, lock: sync.RWMutex{},
} }
@@ -58,6 +66,7 @@ func NewDocker() (Connector, error) {
log.Debugf("docker-connector ServerVersion: %s", info.ServerVersion) log.Debugf("docker-connector ServerVersion: %s", info.ServerVersion)
go cm.Loop() go cm.Loop()
go cm.LoopStatuses()
cm.refreshAll() cm.refreshAll()
go cm.watchEvents() go cm.watchEvents()
return cm, nil return cm, nil
@@ -92,7 +101,7 @@ func (cm *Docker) watchEvents() {
if log.IsEnabledFor(logging.DEBUG) { if log.IsEnabledFor(logging.DEBUG) {
log.Debugf("handling docker event: action=health_status id=%s %s", e.ID, healthStatus) log.Debugf("handling docker event: action=health_status id=%s %s", e.ID, healthStatus)
} }
cm.needsRefresh <- e.ID cm.statuses <- StatusUpdate{e.ID, "health", healthStatus}
case "create": case "create":
if log.IsEnabledFor(logging.DEBUG) { if log.IsEnabledFor(logging.DEBUG) {
log.Debugf("handling docker event: action=create id=%s", e.ID) log.Debugf("handling docker event: action=create id=%s", e.ID)
@@ -110,7 +119,7 @@ func (cm *Docker) watchEvents() {
if log.IsEnabledFor(logging.DEBUG) { if log.IsEnabledFor(logging.DEBUG) {
log.Debugf("handling docker event: action=%s id=%s %s", actionName, e.ID, status) log.Debugf("handling docker event: action=%s id=%s %s", actionName, e.ID, status)
} }
cm.needsRefresh <- e.ID cm.statuses <- StatusUpdate{e.ID, "status", status}
} }
} }
} }
@@ -205,6 +214,24 @@ func (cm *Docker) Loop() {
} }
} }
func (cm *Docker) LoopStatuses() {
for {
select {
case statusUpdate := <-cm.statuses:
c, _ := cm.Get(statusUpdate.Cid)
if c != nil {
if statusUpdate.Field == "health" {
c.SetMeta("health", statusUpdate.Status)
} else {
c.SetState(statusUpdate.Status)
}
}
case <-cm.closed:
return
}
}
}
// MustGet gets a single container, creating one anew if not existing // MustGet gets a single container, creating one anew if not existing
func (cm *Docker) MustGet(id string) *container.Container { func (cm *Docker) MustGet(id string) *container.Container {
c, ok := cm.Get(id) c, ok := cm.Get(id)