mirror of
https://github.com/moby/moby.git
synced 2022-11-09 12:21:53 -05:00
Merge pull request #25043 from stevvooe/forked-pull-context
container/controller: avoid cancellation with forked pull context
This commit is contained in:
commit
7bb9676a2b
1 changed files with 53 additions and 17 deletions
|
@ -24,6 +24,10 @@ type controller struct {
|
||||||
adapter *containerAdapter
|
adapter *containerAdapter
|
||||||
closed chan struct{}
|
closed chan struct{}
|
||||||
err error
|
err error
|
||||||
|
|
||||||
|
pulled chan struct{} // closed after pull
|
||||||
|
cancelPull func() // cancels pull context if not nil
|
||||||
|
pullErr error // pull error, only read after pulled closed
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ exec.Controller = &controller{}
|
var _ exec.Controller = &controller{}
|
||||||
|
@ -86,12 +90,27 @@ func (r *controller) Prepare(ctx context.Context) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
if os.Getenv("DOCKER_SERVICE_PREFER_OFFLINE_IMAGE") != "1" {
|
if os.Getenv("DOCKER_SERVICE_PREFER_OFFLINE_IMAGE") != "1" {
|
||||||
if err := r.adapter.pullImage(ctx); err != nil {
|
if r.pulled == nil {
|
||||||
cause := errors.Cause(err)
|
// Fork the pull to a different context to allow pull to continue
|
||||||
if cause == context.Canceled || cause == context.DeadlineExceeded {
|
// on re-entrant calls to Prepare. This ensures that Prepare can be
|
||||||
return err
|
// idempotent and not incur the extra cost of pulling when
|
||||||
|
// cancelled on updates.
|
||||||
|
var pctx context.Context
|
||||||
|
|
||||||
|
r.pulled = make(chan struct{})
|
||||||
|
pctx, r.cancelPull = context.WithCancel(context.Background()) // TODO(stevvooe): Bind a context to the entire controller.
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
defer close(r.pulled)
|
||||||
|
r.pullErr = r.adapter.pullImage(pctx) // protected by closing r.pulled
|
||||||
|
}()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-ctx.Done():
|
||||||
|
return ctx.Err()
|
||||||
|
case <-r.pulled:
|
||||||
|
if r.pullErr != nil {
|
||||||
// NOTE(stevvooe): We always try to pull the image to make sure we have
|
// NOTE(stevvooe): We always try to pull the image to make sure we have
|
||||||
// the most up to date version. This will return an error, but we only
|
// the most up to date version. This will return an error, but we only
|
||||||
// log it. If the image truly doesn't exist, the create below will
|
// log it. If the image truly doesn't exist, the create below will
|
||||||
|
@ -103,7 +122,8 @@ func (r *controller) Prepare(ctx context.Context) error {
|
||||||
//
|
//
|
||||||
// If you don't want this behavior, lock down your image to an
|
// If you don't want this behavior, lock down your image to an
|
||||||
// immutable tag or digest.
|
// immutable tag or digest.
|
||||||
log.G(ctx).WithError(err).Error("pulling image failed")
|
log.G(ctx).WithError(r.pullErr).Error("pulling image failed")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -252,6 +272,10 @@ func (r *controller) Shutdown(ctx context.Context) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if r.cancelPull != nil {
|
||||||
|
r.cancelPull()
|
||||||
|
}
|
||||||
|
|
||||||
if err := r.adapter.shutdown(ctx); err != nil {
|
if err := r.adapter.shutdown(ctx); err != nil {
|
||||||
if isUnknownContainer(err) || isStoppedContainer(err) {
|
if isUnknownContainer(err) || isStoppedContainer(err) {
|
||||||
return nil
|
return nil
|
||||||
|
@ -269,6 +293,10 @@ func (r *controller) Terminate(ctx context.Context) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if r.cancelPull != nil {
|
||||||
|
r.cancelPull()
|
||||||
|
}
|
||||||
|
|
||||||
if err := r.adapter.terminate(ctx); err != nil {
|
if err := r.adapter.terminate(ctx); err != nil {
|
||||||
if isUnknownContainer(err) {
|
if isUnknownContainer(err) {
|
||||||
return nil
|
return nil
|
||||||
|
@ -286,6 +314,10 @@ func (r *controller) Remove(ctx context.Context) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if r.cancelPull != nil {
|
||||||
|
r.cancelPull()
|
||||||
|
}
|
||||||
|
|
||||||
// It may be necessary to shut down the task before removing it.
|
// It may be necessary to shut down the task before removing it.
|
||||||
if err := r.Shutdown(ctx); err != nil {
|
if err := r.Shutdown(ctx); err != nil {
|
||||||
if isUnknownContainer(err) {
|
if isUnknownContainer(err) {
|
||||||
|
@ -320,6 +352,10 @@ func (r *controller) Close() error {
|
||||||
case <-r.closed:
|
case <-r.closed:
|
||||||
return r.err
|
return r.err
|
||||||
default:
|
default:
|
||||||
|
if r.cancelPull != nil {
|
||||||
|
r.cancelPull()
|
||||||
|
}
|
||||||
|
|
||||||
r.err = exec.ErrControllerClosed
|
r.err = exec.ErrControllerClosed
|
||||||
close(r.closed)
|
close(r.closed)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue