@@ -41,14 +41,19 @@ type Scheduler struct {
4141 goldenMu sync.Mutex
4242
4343 // resumeWaiters tracks sandboxes blocked in Resume (candidates to knock).
44- // Under semantic-score only the highest keepScore waiter may knock at a time.
44+ // Under semantic-score only the highest admit-score waiter may knock at a time.
4545 resumeWaitMu sync.Mutex
46- resumeWaiters map [string ]types. Sandbox
46+ resumeWaiters map [string ]resumeWaiter
4747
4848 // knockMu serializes the single active knocker's Place/Evict/Restore.
4949 knockMu sync.Mutex
5050}
5151
52+ type resumeWaiter struct {
53+ Sandbox types.Sandbox
54+ Since time.Time
55+ }
56+
5257func New (st store.Store , pol policy.Policy , snapRoot string , log * slog.Logger , m * metrics.Metrics , sig * signals.Store ) * Scheduler {
5358 if log == nil {
5459 log = slog .Default ()
@@ -64,7 +69,7 @@ func New(st store.Store, pol policy.Policy, snapRoot string, log *slog.Logger, m
6469 log : log ,
6570 metrics : m ,
6671 signals : sig ,
67- resumeWaiters : make (map [string ]types. Sandbox ),
72+ resumeWaiters : make (map [string ]resumeWaiter ),
6873 }
6974 if m != nil {
7075 m .SetPoolStats (s )
@@ -344,10 +349,11 @@ func (s *Scheduler) Resume(ctx context.Context, id string) (types.Sandbox, error
344349 }
345350 now := time .Now ().UTC ()
346351 sandboxSig , workerSig := s .signalViews (now )
352+ waiting , waitingSince := s .listResumeWaitState ()
347353 res , err := s .policy .Resume (ctx , policy.ResumeRequest {
348354 Sandbox : sb , Workers : workers , Running : running ,
349355 SandboxSignals : sandboxSig , WorkerSignals : workerSig ,
350- Waiting : s . listResumeWaiters () ,
356+ Waiting : waiting , WaitingSince : waitingSince ,
351357 })
352358 if err != nil {
353359 lastErr = err
@@ -373,7 +379,7 @@ func (s *Scheduler) Resume(ctx context.Context, id string) (types.Sandbox, error
373379 "err" , err .Error (),
374380 "running" , len (running ),
375381 "workers" , len (workers ),
376- "waiters" , len (s . listResumeWaiters () ),
382+ "waiters" , len (waiting ),
377383 )
378384 select {
379385 case <- ctx .Done ():
@@ -512,10 +518,12 @@ func (s *Scheduler) ensureKnockerTurn(sb types.Sandbox) error {
512518 }
513519 now := time .Now ().UTC ()
514520 sandboxSig , _ := s .signalViews (now )
521+ waiting , waitingSince := s .listResumeWaitState ()
515522 return ss .RequireBestWaiter (policy.ResumeRequest {
516523 Sandbox : sb ,
517524 SandboxSignals : sandboxSig ,
518- Waiting : s .listResumeWaiters (),
525+ Waiting : waiting ,
526+ WaitingSince : waitingSince ,
519527 })
520528}
521529
@@ -692,9 +700,14 @@ func (s *Scheduler) addResumeWaiter(sb types.Sandbox) {
692700 s .resumeWaitMu .Lock ()
693701 defer s .resumeWaitMu .Unlock ()
694702 if s .resumeWaiters == nil {
695- s .resumeWaiters = make (map [string ]types. Sandbox )
703+ s .resumeWaiters = make (map [string ]resumeWaiter )
696704 }
697- s .resumeWaiters [sb .ID ] = sb
705+ if w , ok := s .resumeWaiters [sb .ID ]; ok {
706+ w .Sandbox = sb
707+ s .resumeWaiters [sb .ID ] = w
708+ return
709+ }
710+ s .resumeWaiters [sb .ID ] = resumeWaiter {Sandbox : sb , Since : time .Now ()}
698711}
699712
700713func (s * Scheduler ) removeResumeWaiter (id string ) {
@@ -703,14 +716,16 @@ func (s *Scheduler) removeResumeWaiter(id string) {
703716 delete (s .resumeWaiters , id )
704717}
705718
706- func (s * Scheduler ) listResumeWaiters () []types.Sandbox {
719+ func (s * Scheduler ) listResumeWaitState () ( []types.Sandbox , map [ string ]time. Time ) {
707720 s .resumeWaitMu .Lock ()
708721 defer s .resumeWaitMu .Unlock ()
709722 out := make ([]types.Sandbox , 0 , len (s .resumeWaiters ))
710- for _ , sb := range s .resumeWaiters {
711- out = append (out , sb )
723+ since := make (map [string ]time.Time , len (s .resumeWaiters ))
724+ for id , w := range s .resumeWaiters {
725+ out = append (out , w .Sandbox )
726+ since [id ] = w .Since
712727 }
713- return out
728+ return out , since
714729}
715730
716731// resumeRetryable reports Place/Resume errors that should keep the knocker retrying.
@@ -729,11 +744,11 @@ func resumeRetryable(err error) bool {
729744func semanticWaitDuration () time.Duration {
730745 v := os .Getenv ("SEMANTIC_WAIT_SEC" )
731746 if v == "" {
732- return 120 * time .Second
747+ return 300 * time .Second
733748 }
734749 sec , err := strconv .Atoi (v )
735750 if err != nil || sec < 0 {
736- return 120 * time .Second
751+ return 300 * time .Second
737752 }
738753 return time .Duration (sec ) * time .Second
739754}
0 commit comments