Skip to content

Commit 2b183fb

Browse files
committed
Fix slow docker warning logic
1 parent fbf257d commit 2b183fb

File tree

3 files changed

+115
-43
lines changed

3 files changed

+115
-43
lines changed

pkg/drivers/kic/oci/cli_runner.go

Lines changed: 71 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -150,16 +150,6 @@ func runCmd(cmd *exec.Cmd, warnSlow ...bool) (*RunResult, error) {
150150
warnTime = 3 * time.Second
151151
}
152152

153-
ctx, cancel := context.WithTimeout(context.Background(), killTime)
154-
defer cancel()
155-
156-
if warn { // convert exec.Command to with context
157-
cmdWithCtx := exec.CommandContext(ctx, cmd.Args[0], cmd.Args[1:]...)
158-
cmdWithCtx.Stdout = cmd.Stdout // copying the original command
159-
cmdWithCtx.Stderr = cmd.Stderr
160-
cmd = cmdWithCtx
161-
}
162-
163153
rr := &RunResult{Args: cmd.Args}
164154
klog.Infof("Run: %v", rr.Command())
165155

@@ -182,31 +172,84 @@ func runCmd(cmd *exec.Cmd, warnSlow ...bool) (*RunResult, error) {
182172
cmd.Stderr = errb
183173

184174
start := time.Now()
185-
err := cmd.Run()
186-
elapsed := time.Since(start)
187-
if warn && !out.JSON && !suppressDockerMessage() {
188-
if elapsed > warnTime {
189-
warnLock.Lock()
190-
_, ok := alreadyWarnedCmds[rr.Command()]
191-
if !ok {
192-
alreadyWarnedCmds[rr.Command()] = true
193-
}
194-
warnLock.Unlock()
175+
var err error
176+
177+
if warn {
178+
// Use a more robust approach with proper timeout handling
179+
ctx, cancel := context.WithTimeout(context.Background(), killTime)
180+
defer cancel()
195181

196-
if !ok {
197-
out.WarningT(`Executing "{{.command}}" took an unusually long time: {{.duration}}`, out.V{"command": rr.Command(), "duration": elapsed})
198-
// Don't show any restarting hint, when running podman locally (on linux, with sudo). Only when having a service.
199-
if cmd.Args[0] != "sudo" {
200-
out.ErrT(style.Tip, `Restarting the {{.name}} service may improve performance.`, out.V{"name": cmd.Args[0]})
182+
// Create command with context for proper cancellation
183+
cmdWithCtx := exec.CommandContext(ctx, cmd.Args[0], cmd.Args[1:]...)
184+
cmdWithCtx.Stdout = cmd.Stdout
185+
cmdWithCtx.Stderr = cmd.Stderr
186+
cmdWithCtx.Env = cmd.Env
187+
cmdWithCtx.Dir = cmd.Dir
188+
189+
// Channel to track completion
190+
done := make(chan error, 1)
191+
var warnTimer *time.Timer
192+
193+
// Start the command in a goroutine
194+
go func() {
195+
done <- cmdWithCtx.Run()
196+
}()
197+
198+
// Set up warning timer
199+
if !out.JSON && !suppressDockerMessage() {
200+
warnTimer = time.AfterFunc(warnTime, func() {
201+
warnLock.Lock()
202+
_, ok := alreadyWarnedCmds[rr.Command()]
203+
if !ok {
204+
alreadyWarnedCmds[rr.Command()] = true
205+
warnLock.Unlock()
206+
207+
// Show immediate warning that the operation is slow
208+
out.WarningT(`"{{.command}}" is taking an unusually long time to respond, please be patient.`, out.V{"command": rr.Command()})
209+
// Don't show any restarting hint, when running podman locally (on linux, with sudo). Only when having a service.
210+
if cmd.Args[0] != "sudo" {
211+
out.ErrT(style.Tip, `If this continues to hang, consider restarting the {{.name}} service.`, out.V{"name": cmd.Args[0]})
212+
}
213+
} else {
214+
warnLock.Unlock()
201215
}
202-
}
216+
})
203217
}
204218

205-
if ctx.Err() == context.DeadlineExceeded {
206-
return rr, context.DeadlineExceeded
219+
// Wait for completion or timeout
220+
select {
221+
case err = <-done:
222+
// Command completed normally
223+
if warnTimer != nil {
224+
warnTimer.Stop()
225+
}
226+
case <-ctx.Done():
227+
// Command timed out
228+
if warnTimer != nil {
229+
warnTimer.Stop()
230+
}
231+
232+
// Kill the process if it's still running
233+
if cmdWithCtx.Process != nil {
234+
klog.Warningf("Killing slow %s process after %v timeout", rr.Command(), killTime)
235+
cmdWithCtx.Process.Kill()
236+
}
237+
238+
out.WarningT(`"{{.command}}" took too long to respond (>{{.duration}}) and was terminated.`, out.V{"command": rr.Command(), "duration": killTime})
239+
if cmd.Args[0] != "sudo" {
240+
out.ErrT(style.Tip, `Consider restarting the {{.name}} service if this problem persists.`, out.V{"name": cmd.Args[0]})
241+
}
242+
243+
return rr, fmt.Errorf("command timed out after %v: %s", killTime, rr.Command())
207244
}
245+
} else {
246+
// Run without timeout for non-critical operations
247+
err = cmd.Run()
208248
}
209249

250+
elapsed := time.Since(start)
251+
252+
// Log completion information
210253
if ex, ok := err.(*exec.ExitError); ok {
211254
klog.Warningf("%s returned with exit code %d", rr.Command(), ex.ExitCode())
212255
rr.ExitCode = ex.ExitCode()

pkg/drivers/kic/oci/oci.go

Lines changed: 41 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -41,54 +41,61 @@ import (
4141
)
4242

4343
// DeleteContainersByLabel deletes all containers that have a specific label
44-
// if there no containers found with the given label, it will return nil
44+
// if there no containers found with the given label, it will return nil
4545
func DeleteContainersByLabel(ociBin string, label string) []error {
4646
var deleteErrs []error
4747
ctx := context.Background()
48-
cs, err := ListContainersByLabel(ctx, ociBin, label)
48+
49+
// Enable slow warning for container listing during delete operations
50+
cs, err := ListContainersByLabel(ctx, ociBin, label, true)
4951
if err != nil {
50-
return []error{fmt.Errorf("listing containers by label %q", label)}
52+
return []error{fmt.Errorf("listing containers by label %q: %v", label, err)}
5153
}
5254

5355
if len(cs) == 0 {
5456
return nil
5557
}
5658

5759
for _, c := range cs {
58-
_, err := ContainerStatus(ociBin, c)
60+
// Enable slow warning for container status check
61+
_, err := ContainerStatus(ociBin, c, true)
5962
// only try to delete if docker/podman inspect returns
6063
// if it doesn't it means docker daemon is stuck and needs restart
6164
if err != nil {
6265
deleteErrs = append(deleteErrs, errors.Wrapf(err, "delete container %s: %s daemon is stuck. please try again", c, ociBin))
6366
klog.Errorf("%s daemon seems to be stuck. please try restarting your %s :%v", ociBin, ociBin, err)
6467
continue
6568
}
69+
6670
if err := ShutDown(ociBin, c); err != nil {
6771
klog.Infof("couldn't shut down %s (might be okay): %v ", c, err)
6872
}
6973

70-
if _, err := runCmd(exec.Command(ociBin, "rm", "-f", "-v", c)); err != nil {
74+
// Enable slow warning for container removal
75+
if _, err := runCmd(exec.Command(ociBin, "rm", "-f", "-v", c), true); err != nil {
7176
deleteErrs = append(deleteErrs, errors.Wrapf(err, "delete container %s: output %s", c, err))
7277
}
73-
7478
}
7579
return deleteErrs
7680
}
7781

7882
// DeleteContainer deletes a container by ID or Name
7983
func DeleteContainer(ctx context.Context, ociBin string, name string) error {
80-
_, err := ContainerStatus(ociBin, name)
84+
// Enable slow warning for container status check
85+
_, err := ContainerStatus(ociBin, name, true)
8186
if err == context.DeadlineExceeded {
82-
out.WarningT("{{.ocibin}} is taking an unusually long time to respond, consider restarting {{.ocibin}}", out.V{"ociBin": ociBin})
87+
out.WarningT("{{.ocibin}} is taking an unusually long time to respond, consider restarting {{.ocibin}}", out.V{"ocibin": ociBin})
8388
} else if err != nil {
8489
klog.Warningf("error getting container status, will try to delete anyways: %v", err)
8590
}
91+
8692
// try to delete anyways
8793
if err := ShutDown(ociBin, name); err != nil {
8894
klog.Infof("couldn't shut down %s (might be okay): %v ", name, err)
8995
}
9096

91-
if _, err := runCmd(exec.CommandContext(ctx, ociBin, "rm", "-f", "-v", name)); err != nil {
97+
// Enable slow warning for container removal
98+
if _, err := runCmd(exec.CommandContext(ctx, ociBin, "rm", "-f", "-v", name), true); err != nil {
9299
return errors.Wrapf(err, "delete %s", name)
93100
}
94101
return nil
@@ -368,7 +375,12 @@ func ContainerID(ociBin string, nameOrID string) (string, error) {
368375

369376
// ContainerExists checks if container name exists (either running or exited)
370377
func ContainerExists(ociBin string, name string, warnSlow ...bool) (bool, error) {
371-
rr, err := runCmd(exec.Command(ociBin, "ps", "-a", "--format", "{{.Names}}"), warnSlow...)
378+
shouldWarn := false
379+
if len(warnSlow) > 0 {
380+
shouldWarn = warnSlow[0]
381+
}
382+
383+
rr, err := runCmd(exec.Command(ociBin, "ps", "-a", "--format", "{{.Names}}"), shouldWarn)
372384
if err != nil {
373385
return false, err
374386
}
@@ -540,7 +552,13 @@ func withPortMappings(portMappings []PortMapping) createOpt {
540552

541553
// ListContainersByLabel returns all the container names with a specified label
542554
func ListContainersByLabel(ctx context.Context, ociBin string, label string, warnSlow ...bool) ([]string, error) {
543-
rr, err := runCmd(exec.CommandContext(ctx, ociBin, "ps", "-a", "--filter", fmt.Sprintf("label=%s", label), "--format", "{{.Names}}"), warnSlow...)
555+
// Default to enabling warnings for container listing operations during critical operations like delete
556+
shouldWarn := false
557+
if len(warnSlow) > 0 {
558+
shouldWarn = warnSlow[0]
559+
}
560+
561+
rr, err := runCmd(exec.CommandContext(ctx, ociBin, "ps", "-a", "--filter", fmt.Sprintf("label=%s", label), "--format", "{{.Names}}"), shouldWarn)
544562
if err != nil {
545563
return nil, err
546564
}
@@ -619,7 +637,12 @@ func PointToHostPodman() error {
619637

620638
// ContainerRunning returns running state of a container
621639
func ContainerRunning(ociBin string, name string, warnSlow ...bool) (bool, error) {
622-
rr, err := runCmd(exec.Command(ociBin, "container", "inspect", name, "--format={{.State.Running}}"), warnSlow...)
640+
shouldWarn := false
641+
if len(warnSlow) > 0 {
642+
shouldWarn = warnSlow[0]
643+
}
644+
645+
rr, err := runCmd(exec.Command(ociBin, "container", "inspect", name, "--format={{.State.Running}}"), shouldWarn)
623646
if err != nil {
624647
return false, err
625648
}
@@ -628,8 +651,13 @@ func ContainerRunning(ociBin string, name string, warnSlow ...bool) (bool, error
628651

629652
// ContainerStatus returns status of a container running,exited,...
630653
func ContainerStatus(ociBin string, name string, warnSlow ...bool) (state.State, error) {
654+
shouldWarn := false
655+
if len(warnSlow) > 0 {
656+
shouldWarn = warnSlow[0]
657+
}
658+
631659
cmd := exec.Command(ociBin, "container", "inspect", name, "--format={{.State.Status}}")
632-
rr, err := runCmd(cmd, warnSlow...)
660+
rr, err := runCmd(cmd, shouldWarn)
633661
o := strings.TrimSpace(rr.Stdout.String())
634662
switch o {
635663
case "configured":

pkg/minikube/delete/delete.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,15 +47,16 @@ func PossibleLeftOvers(ctx context.Context, cname string, driverName string) {
4747

4848
klog.Infof("deleting possible leftovers for %s (driver=%s) ...", cname, driverName)
4949
delLabel := fmt.Sprintf("%s=%s", oci.ProfileLabelKey, cname)
50-
cs, err := oci.ListContainersByLabel(ctx, bin, delLabel)
50+
51+
// Enable slow warning for container listing during delete operations
52+
cs, err := oci.ListContainersByLabel(ctx, bin, delLabel, true)
5153
if err == nil && len(cs) > 0 {
5254
for _, c := range cs {
5355
out.Step(style.DeletingHost, `Deleting container "{{.name}}" ...`, out.V{"name": cname})
5456
err := oci.DeleteContainer(ctx, bin, c)
5557
if err != nil { // it will error if there is no container to delete
5658
klog.Errorf("error deleting container %q. You may want to delete it manually :\n%v", cname, err)
5759
}
58-
5960
}
6061
}
6162

0 commit comments

Comments
 (0)