diff --git a/daemon/monitor.go b/daemon/monitor.go index ba9d513745..1507a337d6 100644 --- a/daemon/monitor.go +++ b/daemon/monitor.go @@ -27,7 +27,10 @@ func (daemon *Daemon) setStateCounter(c *container.Container) { } func (daemon *Daemon) handleContainerExit(c *container.Container, e *libcontainerdtypes.EventInfo) error { - var exitStatus container.ExitStatus + var ( + exitStatus container.ExitStatus + taskDeletionDone chan struct{} + ) c.Lock() cfg := daemon.config() @@ -38,19 +41,33 @@ func (daemon *Daemon) handleContainerExit(c *container.Container, e *libcontaine tsk, ok := c.Task() if ok { - ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) - es, err := tsk.Delete(ctx) - cancel() - if err != nil { - log.G(ctx).WithFields(log.Fields{ - "error": err, - "container": c.ID, - }).Warn("failed to delete container from containerd") - } else { - exitStatus = container.ExitStatus{ - ExitCode: int(es.ExitCode()), - ExitedAt: es.ExitTime(), + taskDeletionDone = make(chan struct{}) + go func() { + defer close(taskDeletionDone) + ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) + es, err := tsk.Delete(ctx) + cancel() + if err != nil { + log.G(ctx).WithFields(log.Fields{ + "error": err, + "container": c.ID, + }).Warn("failed to delete container from containerd") + } else { + exitStatus = container.ExitStatus{ + ExitCode: int(es.ExitCode()), + ExitedAt: es.ExitTime(), + } } + }() + + deletionIOCloseTimeout := time.NewTimer(3 * time.Second) + select { + case <-taskDeletionDone: + deletionIOCloseTimeout.Stop() + case <-deletionIOCloseTimeout.C: + // if tsk.Delete(ctx) did not exit after 3 seconds, try to close IO + // streams - they may be blocking the deletion - and continue + // waiting after that } } @@ -62,6 +79,10 @@ func (daemon *Daemon) handleContainerExit(c *container.Container, e *libcontaine c.Reset(ctx, false) cancel() + if taskDeletionDone != nil { + <-taskDeletionDone + } + if e != nil { exitStatus.ExitCode = int(e.ExitCode) exitStatus.ExitedAt = e.ExitedAt