Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Feat]: Pull images with background Contexts #2505

Open
Namnamseo opened this issue Jun 29, 2024 · 2 comments
Open

[Feat]: Pull images with background Contexts #2505

Namnamseo opened this issue Jun 29, 2024 · 2 comments
Labels
feature New feature or request rm-external Roadmap item submitted by non-maintainers

Comments

@Namnamseo
Copy link

Is your feature request related to a problem? Please describe.

cf. #2416

When an on-demand sync is triggered, the ctx to the call to SyncImage() comes from the request context.Context.
Thus, when the user gives up, the image sync is also canceled.

Code flow:

content, digest, mediaType, err := getImageManifest(request.Context(), rh, imgStore, name, reference)

if errSync := routeHandler.c.SyncOnDemand.SyncImage(ctx, name, reference); errSync != nil {

go onDemand.syncImage(ctx, repo, reference, syncResult)

manifestDigest, err := service.syncTag(ctx, repo, remoteRepo, reference)

This is unfortunate, I think, in many use cases where Zot is used as a proxy cache.
Even if we couldn't make it on time this time, it isn't that we don't want to have this image cached.

If the client has a timeout limit and a retry loop (like common setups with Kubernetes and containerd do - at least in mine), the current implementation will not be able to make any progress.
This is because, as soon as the client hits the timeout, the sync job fails (because it makes an HTTP request with a canceled Context, I guess), and when the client retries, the sync has to start over again.

It would be better if the pull keeps running in the background, so that the next time there's a request to this image, they could wait for the remaining progress and have any chance of seeing it finish.
Note that the current logic already supports the joining (to wait) to an ongoing pull in another goroutine:

val, found := onDemand.requestStore.Load(req)
if found {
onDemand.log.Info().Str("repo", repo).Str("reference", reference).
Msg("image already demanded, waiting on channel")
syncResult, _ := val.(chan error)
err, ok := <-syncResult

Describe the solution you'd like

Somewhere during the code flow, use a background Context instead of the request Context.
Note that we do not want to completely ignore the request Context; we need to halt the control flow and return when the request is canceled.

A good place could be here:

go onDemand.syncImage(ctx, repo, reference, syncResult)
err, ok := <-syncResult
if !ok {
return nil
}

We could give syncImage a context.Background(), or a larger timeout (15 minutes?).
Then, below, a select {} with both syncResult and ctx.Done() would suffice.

Describe alternatives you've considered

Since we're spawning a goroutine on every cache miss, this could lead to a large number of background goroutines.
In that prospect, having a full-fledged background process controller (like limiting the number, etc.) could be a long-term goal.

Additional context

The image size in question is ~10 GiB, and network speed is as low as 10 MiB/s. That would take 1k seconds (= 16m 40s).

@Namnamseo Namnamseo added the feature New feature or request label Jun 29, 2024
@Namnamseo
Copy link
Author

I didn't go right into writing a PR because I'm not familiar with the code base and am not sure if this is OK.
The leaky goroutine thing feels a bit dangerous so I'd like more opinions on this.

Once there's a resolution, I'd be happy to come up with a PR.

@rchincha rchincha added the rm-external Roadmap item submitted by non-maintainers label Jun 29, 2024
@eusebiu-constantin-petu-dbk
Copy link
Collaborator

I agree with your points, you can make this update if you want. I'll review it.

Thank you!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature New feature or request rm-external Roadmap item submitted by non-maintainers
Projects
None yet
Development

No branches or pull requests

3 participants