From 72c9d0dd284d78856704edc10777ba66a71b72ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Philippe=20Qu=C3=A9m=C3=A9ner?= Date: Thu, 20 Mar 2025 11:15:13 +0100 Subject: [PATCH] fix(unified-storage): use new context for background operations (#102518) --- pkg/storage/legacysql/dualwrite/dualwriter.go | 27 ++++++++++++++----- 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/pkg/storage/legacysql/dualwrite/dualwriter.go b/pkg/storage/legacysql/dualwrite/dualwriter.go index 73db580ece5..c34609cc9f5 100644 --- a/pkg/storage/legacysql/dualwrite/dualwriter.go +++ b/pkg/storage/legacysql/dualwrite/dualwriter.go @@ -3,6 +3,7 @@ package dualwrite import ( "context" "fmt" + "time" apierrors "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/api/meta" @@ -20,6 +21,8 @@ var ( _ grafanarest.Storage = (*dualWriter)(nil) ) +const backgroundReqTimeout = 5 * time.Second + // dualWriter will write first to legacy, then to unified keeping the same internal ID type dualWriter struct { legacy grafanarest.Storage @@ -43,7 +46,9 @@ func (d *dualWriter) Get(ctx context.Context, name string, options *metav1.GetOp // If we allow the unified read to fail, we can do it in the background. if d.errorIsOK { go func() { - if _, err := d.unified.Get(ctx, name, options); err != nil { + ctxBg, cancel := context.WithTimeout(context.Background(), backgroundReqTimeout) + defer cancel() + if _, err := d.unified.Get(ctxBg, name, options); err != nil { d.log.Error("failed background GET to unified", "err", err) } }() @@ -71,7 +76,9 @@ func (d *dualWriter) List(ctx context.Context, options *metainternalversion.List // If we allow the unified list to fail, we can do it in the background and return. if d.errorIsOK { go func() { - if _, err := d.unified.List(ctx, options); err != nil { + ctxBg, cancel := context.WithTimeout(context.Background(), backgroundReqTimeout) + defer cancel() + if _, err := d.unified.List(ctxBg, options); err != nil { d.log.Error("failed background LIST to unified", "err", err) } }() @@ -133,7 +140,9 @@ func (d *dualWriter) Create(ctx context.Context, in runtime.Object, createValida } else if d.errorIsOK { // If we don't use unified as the primary store and errors are okay, let's create it in the background. go func() { - if _, err := d.unified.Create(ctx, createdCopy, createValidation, options); err != nil { + ctxBg, cancel := context.WithTimeout(context.Background(), backgroundReqTimeout) + defer cancel() + if _, err := d.unified.Create(ctxBg, createdCopy, createValidation, options); err != nil { log.Error("unable to create object in unified storage", "err", err) } }() @@ -177,7 +186,9 @@ func (d *dualWriter) Delete(ctx context.Context, name string, deleteValidation r } else if d.errorIsOK { // If errors are okay and unified is not primary, we can just run it as background operation. go func() { - _, _, err := d.unified.Delete(ctx, name, deleteValidation, options) + ctxBg, cancel := context.WithTimeout(context.Background(), backgroundReqTimeout) + defer cancel() + _, _, err := d.unified.Delete(ctxBg, name, deleteValidation, options) if err != nil && !apierrors.IsNotFound(err) && !d.errorIsOK { d.log.Error("failed background DELETE in unified storage", "err", err) } @@ -216,7 +227,9 @@ func (d *dualWriter) Update(ctx context.Context, name string, objInfo rest.Updat } else if d.errorIsOK { // If unified is not primary, but errors are okay, we can just run in the background. go func() { - if _, _, err := d.unified.Update(ctx, name, objInfo, createValidation, updateValidation, forceAllowCreate, options); err != nil { + ctxBg, cancel := context.WithTimeout(context.Background(), backgroundReqTimeout) + defer cancel() + if _, _, err := d.unified.Update(ctxBg, name, objInfo, createValidation, updateValidation, forceAllowCreate, options); err != nil { log.Error("failed background UPDATE to unified storage", "err", err) } }() @@ -251,7 +264,9 @@ func (d *dualWriter) DeleteCollection(ctx context.Context, deleteValidation rest } else if d.errorIsOK { // If unified storage is not the primary store and errors are okay, we can just run it in the background. go func() { - if _, err := d.unified.DeleteCollection(ctx, deleteValidation, options, listOptions); err != nil { + ctxBg, cancel := context.WithTimeout(context.Background(), backgroundReqTimeout) + defer cancel() + if _, err := d.unified.DeleteCollection(ctxBg, deleteValidation, options, listOptions); err != nil { log.Error("failed background DELETE collection to unified storage", "err", err) } }()