fix this insane CPU usage issue

pull/1/head
Jesse Duffield 5 years ago
parent 46d27c477e
commit 159a1883e5

@ -9,6 +9,7 @@ import (
"github.com/docker/docker/api/types"
"github.com/docker/docker/client"
"github.com/fatih/color"
"github.com/go-errors/errors"
"github.com/jesseduffield/lazydocker/pkg/utils"
"github.com/sirupsen/logrus"
"golang.org/x/xerrors"
@ -298,9 +299,14 @@ func (c *Container) RestartService() error {
}
// Attach attaches the container
func (c *Container) Attach() *exec.Cmd {
func (c *Container) Attach() (*exec.Cmd, error) {
// verify that we can in fact attach to this container
if !c.Details.Config.AttachStdin {
return nil, errors.New("Container does not support attaching. You must either run the service with the '-it' flag or use `stdin_open: true, tty: true` in the docker-compose.yml file")
}
cmd := c.OSCommand.PrepareSubProcess("docker", "attach", "--sig-proxy=false", c.ID)
return cmd
return cmd, nil
}
// Top returns process information

@ -78,16 +78,22 @@ func (c *DockerCommand) UpdateContainerStats(containers []*Container) ([]*Contai
}
// GetContainersAndServices returns a slice of docker containers
func (c *DockerCommand) GetContainersAndServices() ([]*Container, []*Service, error) {
func (c *DockerCommand) GetContainersAndServices(currentServices []*Service) ([]*Container, []*Service, error) {
containers, err := c.GetContainers()
if err != nil {
return nil, nil, err
}
services, err := c.GetServices()
if err != nil {
return nil, nil, err
var services []*Service
// we only need to get these services once because they won't change in the runtime of the program
if currentServices != nil {
services = currentServices
} else {
services, err = c.GetServices()
if err != nil {
return nil, nil, err
}
}
// find out which services have corresponding containers and assign them
@ -170,8 +176,10 @@ func (c *DockerCommand) GetServices() ([]*Service, error) {
for i, str := range lines {
arr := strings.Split(str, " ")
services[i] = &Service{
Name: arr[0],
ID: arr[1],
Name: arr[0],
ID: arr[1],
OSCommand: c.OSCommand,
Log: c.Log,
}
}

@ -11,12 +11,11 @@ import (
// Service : A docker Service
type Service struct {
Name string
ID string
DisplayString string
OSCommand *OSCommand
Log *logrus.Entry
Container *Container
Name string
ID string
OSCommand *OSCommand
Log *logrus.Entry
Container *Container
}
// GetDisplayStrings returns the dispaly string of Container
@ -50,7 +49,7 @@ func (s *Service) Restart() error {
}
// Attach attaches to the service
func (s *Service) Attach() *exec.Cmd {
func (s *Service) Attach() (*exec.Cmd, error) {
// TODO: if you have a custom command for attaching to a service here is the place to use it
return s.Container.Attach()

@ -102,6 +102,7 @@ type CommandTemplatesConfig struct {
RestartService string `yaml:"restartService,omitempty"`
DockerCompose string `yaml:"dockerCompose,omitempty"`
StopService string `yaml:"stopService,omitempty"`
ServiceLogs string `yaml:"serviceLogs,omitempty"`
}
type OSConfig struct {
@ -132,6 +133,7 @@ func GetDefaultConfig() UserConfig {
RestartService: "docker-compose restart {{ .Name }}",
DockerCompose: "apdev compose",
StopService: "apdev stop {{ .Name }}",
ServiceLogs: "apdev logs {{ .Name }}",
},
OS: GetPlatformDefaultConfig(),
Update: UpdateConfig{

@ -220,13 +220,11 @@ func (gui *Gui) renderLogsForTTYContainer(mainView *gocui.View, container *comma
}
go func() {
for {
s := bufio.NewScanner(r)
s.Split(bufio.ScanLines)
for s.Scan() {
// I might put a check on the stopped channel here. Would mean more code duplication though
mainView.Write(append(s.Bytes(), '\n'))
}
s := bufio.NewScanner(r)
s.Split(bufio.ScanLines)
for s.Scan() {
// I might put a check on the stopped channel here. Would mean more code duplication though
mainView.Write(append(s.Bytes(), '\n'))
}
}()
@ -297,7 +295,7 @@ func (gui *Gui) refreshContainersAndServices() error {
}
func (gui *Gui) refreshStateContainersAndServices() error {
containers, services, err := gui.DockerCommand.GetContainersAndServices()
containers, services, err := gui.DockerCommand.GetContainersAndServices(gui.State.Services)
if err != nil {
return err
}
@ -457,7 +455,10 @@ func (gui *Gui) handleContainerAttach(g *gocui.Gui, v *gocui.View) error {
return nil
}
c := container.Attach()
c, err := container.Attach()
if err != nil {
return gui.createErrorPanel(gui.g, err.Error())
}
gui.SubProcess = c
return gui.Errors.ErrSubProcess

@ -155,7 +155,7 @@ func NewGui(log *logrus.Entry, dockerCommand *commands.DockerCommand, oSCommand
Config: config,
Tr: tr,
statusManager: &statusManager{},
T: tasks.NewTaskManager(),
T: tasks.NewTaskManager(log),
}
gui.GenerateSentinelErrors()
@ -415,7 +415,7 @@ func (gui *Gui) layout(g *gocui.Gui) error {
return err
}
if err := gui.switchFocus(gui.g, nil, gui.getContainersView()); err != nil {
if err := gui.switchFocus(gui.g, nil, gui.getServicesView()); err != nil {
return err
}
}

@ -119,7 +119,16 @@ func (gui *Gui) renderServiceStats(mainView *gocui.View, service *commands.Servi
}
func (gui *Gui) renderServiceLogs(mainView *gocui.View, service *commands.Service) error {
return nil
service, err := gui.getSelectedService(gui.g)
if err != nil {
return nil
}
if service.Container == nil {
return nil
}
return gui.renderContainerLogs(gui.getMainView(), service.Container)
}
func (gui *Gui) handleServicesNextLine(g *gocui.Gui, v *gocui.View) error {
@ -255,7 +264,10 @@ func (gui *Gui) handleServiceAttach(g *gocui.Gui, v *gocui.View) error {
return nil
}
c := service.Attach()
c, err := service.Attach()
if err != nil {
return gui.createErrorPanel(gui.g, err.Error())
}
gui.SubProcess = c
return gui.Errors.ErrSubProcess

@ -7,15 +7,10 @@ import (
"github.com/jesseduffield/gocui"
)
func (gui *Gui) refreshStatus(g *gocui.Gui) error {
v, err := g.View("status")
if err != nil {
panic(err)
}
// for some reason if this isn't wrapped in an update the clear seems to
// be applied after the other things or something like that; the panel's
// contents end up cleared
g.Update(func(*gocui.Gui) error {
func (gui *Gui) refreshStatus() error {
v := gui.getStatusView()
gui.g.Update(func(*gocui.Gui) error {
v.Clear()
fmt.Fprint(v, "lazydocker")
return nil

@ -19,6 +19,10 @@ func (gui *Gui) refreshSidePanels(g *gocui.Gui) error {
if err := gui.refreshImages(); err != nil {
return err
}
if err := gui.refreshStatus(); err != nil {
return err
}
return nil
}
@ -245,6 +249,11 @@ func (gui *Gui) getMainView() *gocui.View {
return v
}
func (gui *Gui) getStatusView() *gocui.View {
v, _ := gui.g.View("status")
return v
}
func (gui *Gui) trimmedContent(v *gocui.View) string {
return strings.TrimSpace(v.Buffer())
}

@ -1,27 +1,38 @@
package tasks
import "sync"
import (
"sync"
"github.com/sirupsen/logrus"
)
type TaskManager struct {
waitingTasks []*Task
currentTask *Task
waitingMutex sync.Mutex
Log *logrus.Entry
}
type Task struct {
stop chan struct{}
notifyStopped chan struct{}
Log *logrus.Entry
}
func NewTaskManager() *TaskManager {
return &TaskManager{}
func NewTaskManager(log *logrus.Entry) *TaskManager {
return &TaskManager{Log: log}
}
func (t *TaskManager) NewTask(f func(stop chan struct{})) error {
t.Log.Warn("new task")
t.waitingMutex.Lock()
defer t.waitingMutex.Unlock()
t.Log.Warn("locked mutex")
if t.currentTask != nil {
t.Log.Warn("about to ask current task to stop")
t.currentTask.Stop()
}
@ -31,9 +42,11 @@ func (t *TaskManager) NewTask(f func(stop chan struct{})) error {
t.currentTask = &Task{
stop: stop,
notifyStopped: notifyStopped,
Log: t.Log,
}
go func() {
t.Log.Warn("running new task")
f(stop)
notifyStopped <- struct{}{}
}()
@ -44,5 +57,6 @@ func (t *TaskManager) NewTask(f func(stop chan struct{})) error {
func (t *Task) Stop() {
t.stop <- struct{}{}
<-t.notifyStopped
t.Log.Warn("task successfully stopped")
return
}

Loading…
Cancel
Save