From 07eaa8b369c99d29c6661697232809649cd906f5 Mon Sep 17 00:00:00 2001 From: Patrick Ohly Date: Tue, 30 Jun 2026 10:20:31 +0200 Subject: [PATCH] restmapper + discovery: early return in context-aware APIs The rationale for explicit cancellation checks is that these functions have side effects that can be avoided when checking upfront. These side effects can still occur when cancellation happens while the functions are executing, but "already canceled" is common enough that it deserves special handling. Kubernetes-commit: c3f63fc258b73e487da7ca84c40be43fc4c5f4dd --- discovery/cached/memory/memcache.go | 4 ++++ discovery/discovery_client.go | 12 ++++++++++++ openapi/cached/client.go | 4 ++++ openapi/cached/groupversion.go | 4 ++++ 4 files changed, 24 insertions(+) diff --git a/discovery/cached/memory/memcache.go b/discovery/cached/memory/memcache.go index 9f2420929..9334cafe5 100644 --- a/discovery/cached/memory/memcache.go +++ b/discovery/cached/memory/memcache.go @@ -169,6 +169,10 @@ func (d *memCacheClient) GroupsAndMaybeResources() (*metav1.APIGroupList, map[sc // to resources. The returned groups will never be nil, but the resources map can be nil // if there are no cached resources. func (d *memCacheClient) GroupsAndMaybeResourcesWithContext(ctx context.Context) (*metav1.APIGroupList, map[schema.GroupVersion]*metav1.APIResourceList, map[schema.GroupVersion]error, error) { + if err := ctx.Err(); err != nil { + return nil, nil, nil, err + } + d.lock.Lock() defer d.lock.Unlock() diff --git a/discovery/discovery_client.go b/discovery/discovery_client.go index f89196e18..25d1cc57c 100644 --- a/discovery/discovery_client.go +++ b/discovery/discovery_client.go @@ -607,6 +607,10 @@ func (d *DiscoveryClient) GroupsAndMaybeResourcesWithContext(ctx context.Context map[schema.GroupVersion]*metav1.APIResourceList, map[schema.GroupVersion]error, error) { + if err := ctx.Err(); err != nil { + return nil, nil, nil, err + } + // Legacy group ordered first (there is only one -- core/v1 group). Returned groups must // be non-nil, but it could be empty. Returned resources, apiResources map could be nil. groups, resources, failedGVs, err := d.downloadLegacy(ctx) @@ -887,6 +891,10 @@ func ServerGroupsAndResources(d DiscoveryInterface) ([]*metav1.APIGroup, []*meta } func ServerGroupsAndResourcesWithContext(ctx context.Context, d DiscoveryInterfaceWithContext) ([]*metav1.APIGroup, []*metav1.APIResourceList, error) { + if err := ctx.Err(); err != nil { + return nil, nil, err + } + var sgs *metav1.APIGroupList var resources []*metav1.APIResourceList var failedGVs map[schema.GroupVersion]error @@ -960,6 +968,10 @@ func ServerPreferredResources(d DiscoveryInterface) ([]*metav1.APIResourceList, // ServerPreferredResourcesWithContext uses the provided discovery interface to look up preferred resources func ServerPreferredResourcesWithContext(ctx context.Context, d DiscoveryInterfaceWithContext) ([]*metav1.APIResourceList, error) { + if err := ctx.Err(); err != nil { + return nil, err + } + var serverGroupList *metav1.APIGroupList var failedGroups map[schema.GroupVersion]error var groupVersionResources map[schema.GroupVersion]*metav1.APIResourceList diff --git a/openapi/cached/client.go b/openapi/cached/client.go index 919883311..5ce47af6f 100644 --- a/openapi/cached/client.go +++ b/openapi/cached/client.go @@ -70,6 +70,10 @@ func (c *Client) Paths() (map[string]openapi.GroupVersion, error) { } func (c *Client) PathsWithContext(ctx context.Context) (map[string]openapi.GroupVersionWithContext, error) { + if err := ctx.Err(); err != nil { + return nil, err + } + c.once.Do(func() { uncached, err := c.delegate.PathsWithContext(ctx) if err != nil { diff --git a/openapi/cached/groupversion.go b/openapi/cached/groupversion.go index 2b1dcf86b..94fe7f056 100644 --- a/openapi/cached/groupversion.go +++ b/openapi/cached/groupversion.go @@ -55,6 +55,10 @@ func (g *groupversion) Schema(contentType string) ([]byte, error) { } func (g *groupversion) SchemaWithContext(ctx context.Context, contentType string) ([]byte, error) { + if err := ctx.Err(); err != nil { + return nil, err + } + g.lock.Lock() defer g.lock.Unlock()