Skip to content

Commit d48b361

Browse files
committed
feat(registry): implement transport caching and clear cache on registry updates
- Added transport caching to optimize HTTP transport reuse for registry endpoints. - Implemented ClearTransportCache function to clear the transport cache when registry configurations change, ensuring fresh transports are used. - Enhanced GetTransport method to utilize cached transports, improving performance and reducing overhead. Signed-off-by: rainsun <[email protected]>
1 parent e816c49 commit d48b361

File tree

2 files changed

+72
-3
lines changed

2 files changed

+72
-3
lines changed

registry-scanner/pkg/registry/config.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,10 @@ func clearRegistries() {
3535
registryLock.Lock()
3636
registries = make(map[string]*RegistryEndpoint)
3737
registryLock.Unlock()
38+
39+
// Also clear transport cache when registries are cleared
40+
// This ensures that when registry configuration changes, we use fresh transports
41+
ClearTransportCache()
3842
}
3943

4044
// LoadRegistryConfiguration loads a YAML-formatted registry configuration from

registry-scanner/pkg/registry/endpoints.go

Lines changed: 68 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import (
1414

1515
"go.uber.org/ratelimit"
1616
"golang.org/x/sync/singleflight"
17+
memcache "github.com/patrickmn/go-cache"
1718
)
1819

1920
// TagListSort defines how the registry returns the list of tags
@@ -121,6 +122,10 @@ var registryLock sync.RWMutex
121122
// credentialGroup ensures only one credential refresh happens per registry
122123
var credentialGroup singleflight.Group
123124

125+
// Transport cache to avoid creating new transports for each request
126+
// Using go-cache with 30 minute expiration and 10 minute cleanup interval
127+
var transportCache = memcache.New(30*time.Minute, 10*time.Minute)
128+
124129
func AddRegistryEndpointFromConfig(epc RegistryConfiguration) error {
125130
ep := NewRegistryEndpoint(epc.Prefix, epc.Name, epc.ApiURL, epc.Credentials, epc.DefaultNS, epc.Insecure, TagListSortFromString(epc.TagSortMode), epc.Limit, epc.CredsExpire)
126131
return AddRegistryEndpoint(ep)
@@ -282,16 +287,76 @@ func (ep *RegistryEndpoint) DeepCopy() *RegistryEndpoint {
282287
return newEp
283288
}
284289

290+
// ClearTransportCache clears the transport cache
291+
// This is useful when registry configuration changes
292+
func ClearTransportCache() {
293+
transportCache.Flush()
294+
}
295+
285296
// GetTransport returns a transport object for this endpoint
297+
// Implements connection pooling and reuse to avoid creating new transports for each request
286298
func (ep *RegistryEndpoint) GetTransport() *http.Transport {
299+
// Check if we have a cached transport for this registry
300+
if cachedTransport, found := transportCache.Get(ep.RegistryAPI); found {
301+
transport := cachedTransport.(*http.Transport)
302+
log.Debugf("Transport cache HIT for %s: %p", ep.RegistryAPI, transport)
303+
304+
// Validate that the transport is still usable
305+
if isTransportValid(transport) {
306+
return transport
307+
}
308+
309+
// Transport is stale, remove it from cache
310+
log.Debugf("Transport for %s is stale, removing from cache", ep.RegistryAPI)
311+
transportCache.Delete(ep.RegistryAPI)
312+
}
313+
314+
log.Debugf("Transport cache MISS for %s", ep.RegistryAPI)
315+
316+
// Create a new transport with optimized connection pool settings
287317
tlsC := &tls.Config{}
288318
if ep.Insecure {
289319
tlsC.InsecureSkipVerify = true
290320
}
291-
return &http.Transport{
292-
Proxy: http.ProxyFromEnvironment,
293-
TLSClientConfig: tlsC,
321+
322+
// Create transport with aggressive timeout and connection management
323+
transport := &http.Transport{
324+
Proxy: http.ProxyFromEnvironment,
325+
TLSClientConfig: tlsC,
326+
MaxIdleConns: 20, // Reduced global max idle connections
327+
MaxIdleConnsPerHost: 5, // Reduced per-host connections
328+
IdleConnTimeout: 30 * time.Second, // Reduced idle timeout
329+
TLSHandshakeTimeout: 5 * time.Second, // Reduced TLS timeout
330+
ExpectContinueTimeout: 1 * time.Second, // Expect-Continue timeout
331+
DisableKeepAlives: false, // Enable HTTP Keep-Alive
332+
ForceAttemptHTTP2: true, // Enable HTTP/2 if available
333+
// Critical timeout settings to prevent hanging connections
334+
ResponseHeaderTimeout: 10 * time.Second, // Response header timeout
335+
MaxConnsPerHost: 10, // Limit total connections per host
294336
}
337+
338+
// Cache the transport for reuse with default expiration (30 minutes)
339+
transportCache.Set(ep.RegistryAPI, transport, memcache.DefaultExpiration)
340+
log.Debugf("Cached NEW transport for %s: %p", ep.RegistryAPI, transport)
341+
342+
return transport
343+
}
344+
345+
// isTransportValid checks if a cached transport is still valid and usable
346+
func isTransportValid(transport *http.Transport) bool {
347+
// Basic validation - check if transport is not nil and has valid configuration
348+
if transport == nil {
349+
return false
350+
}
351+
352+
// Check if the transport's connection settings are reasonable
353+
// This is a simple validation, more sophisticated checks could be added
354+
if transport.MaxIdleConns < 0 || transport.MaxIdleConnsPerHost < 0 {
355+
return false
356+
}
357+
358+
// Transport appears to be valid
359+
return true
295360
}
296361

297362
// init initializes the registry configuration

0 commit comments

Comments
 (0)