Repository: containerd/containerd
File: internal/cri/server/container_stop.go (Go)

Code before:
	containerStopTimer.WithValues(i.Runtime.Name).UpdateSince(start)

	return &runtime.StopContainerResponse{}, nil
}

// stopContainerRetryOnConnectionClosed attempts to stop the container.
//
// If the container has already exited and the connection is closed (like, ttrpc: closed),
// it retries up to 3 times since this is a race condition where the container
// self-exited before we attempted to stop it.
func (c *criService) stopContainerRetryOnConnectionClosed(ctx context.Context, container containerstore.Container, timeout time.Duration) error {
	const maxRetries = 3

	var err error
	for i := 0; i < maxRetries; i++ {
		err = c.stopContainer(ctx, container, timeout)
		if err == nil {
			return nil
		}

		if !ctrdutil.IsShimTTRPCClosed(err) {
			return err
		}

		if i+1 < maxRetries {
			retryAfter := time.Duration(500*(i+1)) * time.Millisecond
			log.G(ctx).WithError(err).Warnf("Shim ttrpc connection closed when stopping container %q, retry after %s", container.ID, retryAfter)
			time.Sleep(retryAfter)
		}
	}
	return err
}

// stopContainer stops a container based on the container metadata.
func (c *criService) stopContainer(ctx context.Context, container containerstore.Container, timeout time.Duration) error {
	span := tracing.SpanFromContext(ctx)
	start := time.Now()
	id := container.ID
	sandboxID := container.SandboxID

	// Return without error if container is not running. This makes sure that
	// stop only takes real action after the container is started.
	state := container.Status.Get().State()
	if state != runtime.ContainerState_CONTAINER_RUNNING &&
		state != runtime.ContainerState_CONTAINER_UNKNOWN {
		log.G(ctx).Infof("Container to stop %q must be in running or unknown state, current state %q",
			id, criContainerStateToString(state))
		return nil
	}

	task, err := container.Container.Task(ctx, nil)

Review comment (suggestion):
```suggestion
			retryAfter := time.Duration(100*(i+1)*(i+1)) * time.Millisecond
```
i=0 ... right away, then after 100ms delay, 400ms delay,  finally 900ms delay

Code after:
	containerStopTimer.WithValues(i.Runtime.Name).UpdateSince(start)

	return &runtime.StopContainerResponse{}, nil
}

// stopContainerRetryOnConnectionClosed attempts to stop the container.
//
// If the container has already exited and the connection is closed (like, ttrpc: closed),
// it retries up to 3 times since this is a race condition where the container
// self-exited before we attempted to stop it.
func (c *criService) stopContainerRetryOnConnectionClosed(ctx context.Context, container containerstore.Container, timeout time.Duration) error {
	const maxRetries = 3

	var err error
	for i := 1; i <= maxRetries; i++ {
		err = c.stopContainer(ctx, container, timeout)
		if err == nil {
			return nil
		}

		if !ctrdutil.IsShimTTRPCClosed(err) {
			return err
		}

		if i+1 <= maxRetries {
			retryAfter := time.Duration(100*i*i) * time.Millisecond
			log.G(ctx).WithError(err).Warnf("Shim ttrpc connection closed when stopping container %q, retry after %s", container.ID, retryAfter)
			time.Sleep(retryAfter)
		}
	}
	return err
}

// stopContainer stops a container based on the container metadata.
func (c *criService) stopContainer(ctx context.Context, container containerstore.Container, timeout time.Duration) error {
	span := tracing.SpanFromContext(ctx)
	start := time.Now()
	id := container.ID
	sandboxID := container.SandboxID

	// Return without error if container is not running. This makes sure that
	// stop only takes real action after the container is started.
	state := container.Status.Get().State()
	if state != runtime.ContainerState_CONTAINER_RUNNING &&
		state != runtime.ContainerState_CONTAINER_UNKNOWN {
		log.G(ctx).Infof("Container to stop %q must be in running or unknown state, current state %q",
			id, criContainerStateToString(state))
		return nil
	}

	task, err := container.Container.Task(ctx, nil)