@@ -29,6 +29,13 @@ const workloadLabelKey = "ctrlplane.workload"
2929// reaps via this field.
3030const gcReasonOrphanSwept = "orphan_swept"
3131
32+ // gcStoreCallTimeout caps each individual store roundtrip
33+ // (ListTenants, instances.List, Delete) so a stalled driver session
34+ // can't pin a connection from the shared pool past the next tick.
35+ // 30 seconds is generous for cross-tenant scans on a healthy mongo
36+ // and tight enough that one slow tenant doesn't blind-spot the rest.
37+ const gcStoreCallTimeout = 30 * time .Second
38+
3239// gcReasonTenantFailed tags an event published when a per-tenant
3340// sweep aborted half-way. Lets operators correlate GC error spikes
3441// with specific tenants (e.g. one tenant's storage backend down
@@ -156,7 +163,9 @@ func (g *GarbageCollector) Interval() time.Duration {
156163// the sweep continues to the next tenant — one broken tenant
157164// must not blind-spot the rest.
158165func (g * GarbageCollector ) Run (ctx context.Context ) error {
159- tenants , err := g .tenants .ListTenants (ctx , admin.ListTenantsOptions {Limit : 1000 })
166+ listCtx , listCancel := context .WithTimeout (ctx , gcStoreCallTimeout )
167+ tenants , err := g .tenants .ListTenants (listCtx , admin.ListTenantsOptions {Limit : 1000 })
168+ listCancel ()
160169 if err != nil {
161170 return fmt .Errorf ("gc: list tenants: %w" , err )
162171 }
@@ -206,7 +215,9 @@ func (g *GarbageCollector) Run(ctx context.Context) error {
206215func (g * GarbageCollector ) sweepTenant (ctx context.Context , tenantID string ) (int , error ) {
207216 tCtx := withSystemClaims (ctx , tenantID )
208217
209- res , err := g .instances .List (tCtx , instance.ListOptions {Limit : g .cfg .MaxInstancesPerTick })
218+ listCtx , listCancel := context .WithTimeout (tCtx , gcStoreCallTimeout )
219+ res , err := g .instances .List (listCtx , instance.ListOptions {Limit : g .cfg .MaxInstancesPerTick })
220+ listCancel ()
210221 if err != nil {
211222 return 0 , fmt .Errorf ("list instances: %w" , err )
212223 }
@@ -224,7 +235,10 @@ func (g *GarbageCollector) sweepTenant(ctx context.Context, tenantID string) (in
224235 continue
225236 }
226237
227- if err := g .instances .Delete (tCtx , inst .ID ); err != nil {
238+ delCtx , delCancel := context .WithTimeout (tCtx , gcStoreCallTimeout )
239+ err := g .instances .Delete (delCtx , inst .ID )
240+ delCancel ()
241+ if err != nil {
228242 // Don't abort the tenant sweep on a single Delete
229243 // failure — convergent Delete will retry next tick.
230244 // We still emit a tagged event so operators see the
0 commit comments