fix: throttle image cache progress callback to avoid download bottleneck (#24898)

When using S3/MinIO backend, the progress callback in AcquireImage was
called synchronously on every 4KB read chunk (via StreamPipe2). Each
call invokes UpdateServerProgress which makes a blocking HTTP PUT to the
compute API (~50ms), capping download speed at ~0.65 Mbps regardless of
available bandwidth.

Fix: throttle the callback to fire at most once every 5 seconds and make
the HTTP call asynchronous (goroutine), matching the behavior of v3.11.x
which used a 1-second ticker with async callbacks.

Fixes #24897

Co-authored-by: Mrliuch <liu15094534492@gmail.com>
This commit is contained in:
LiuChen
2026-05-26 15:09:46 +08:00
committed by GitHub
parent 52f84f0cd3
commit 2ad20fff33

View File

@@ -18,6 +18,7 @@ import (
"context" "context"
"os" "os"
"sync" "sync"
"time"
"yunion.io/x/jsonutils" "yunion.io/x/jsonutils"
"yunion.io/x/log" "yunion.io/x/log"
@@ -113,9 +114,11 @@ func (c *SLocalImageCacheManager) AcquireImage(ctx context.Context, input api.Ca
c.cachedImages.Store(input.ImageId, imgObj) c.cachedImages.Store(input.ImageId, imgObj)
} }
if callback == nil && len(input.ServerId) > 0 { if callback == nil && len(input.ServerId) > 0 {
var lastReport time.Time
callback = func(progress, progressMbps float64, totalSizeMb int64) { callback = func(progress, progressMbps float64, totalSizeMb int64) {
if len(input.ServerId) > 0 { if len(input.ServerId) > 0 && time.Since(lastReport) > 5*time.Second {
hostutils.UpdateServerProgress(ctx, input.ServerId, progress, progressMbps) lastReport = time.Now()
go hostutils.UpdateServerProgress(ctx, input.ServerId, progress, progressMbps)
} }
} }
} }