Propagate ctx into memorypullcache image pulls

remote.Image was being called without remote.WithContext, so cancellation
of the workflow ctx (e.g. when ActorWorkflow.ResumeActor hits its 28s
deadline) did not stop the in-flight layer-blob HTTP requests. The
goroutines kept running until the TCP connection was torn down,
retaining partial-blob buffers in the meantime.

On a death loop of ResumeActor retries against a large image, this
amplifies atelet RSS proportionally to the loop duration — observed
peaking at ~9.4GB on a kind node where baseline atelet was ~2.4GB,
enough to OOM atelet on tight production workers.

Fixes #230.
This commit is contained in:
Jonathan Jamroga
2026-06-12 09:09:14 -07:00
committed by Bowei Du
parent a3f44744d3
commit 27aa4eec85
+11 -4
View File
@@ -121,10 +121,17 @@ func (c *MemoryPullCache) Fetch(ctx context.Context, ref string) (io.ReadCloser,
// trips to the registry.
var remoteOptions []remote.Option
remoteOptions = append(remoteOptions, remote.WithPlatform(v1.Platform{
Architecture: runtime.GOARCH,
OS: "linux",
}))
remoteOptions = append(remoteOptions,
// Propagate caller ctx into go-containerregistry so cancellation tears
// down in-flight layer-blob HTTP requests instead of letting them run
// to completion in background goroutines (which retain partial-blob
// buffers and amplify atelet RSS during ResumeActor death loops).
remote.WithContext(ctx),
remote.WithPlatform(v1.Platform{
Architecture: runtime.GOARCH,
OS: "linux",
}),
)
registry := parsedRef.Context().Registry.RegistryStr()
if registry == "gcr.io" || strings.HasSuffix(registry, ".gcr.io") || registry == "pkg.dev" || strings.HasSuffix(registry, ".pkg.dev") {