app/run.go: resolve effective overlap policy per job in RunDue
RunDue now resolves each job's effective overlap policy via effectiveOverlapPolicy (job value when set, else Config.OverlapPolicy) instead of reading the global policy once per tick. An empty Job.OverlapPolicy inherits the global default, so normalizeJobs continues to leave the field untouched rather than backfilling it. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
+14
-3
@@ -67,7 +67,6 @@ func (s *Service) RunDue(now time.Time) {
|
|||||||
var startErr error
|
var startErr error
|
||||||
if !s.paused {
|
if !s.paused {
|
||||||
sequential := s.store.Config.ExecutionMode == domain.ExecutionModeSequential
|
sequential := s.store.Config.ExecutionMode == domain.ExecutionModeSequential
|
||||||
queue := s.store.Config.OverlapPolicy == domain.OverlapPolicyQueue
|
|
||||||
running := s.anyRunningLocked()
|
running := s.anyRunningLocked()
|
||||||
for index := range s.jobs {
|
for index := range s.jobs {
|
||||||
job := &s.jobs[index]
|
job := &s.jobs[index]
|
||||||
@@ -77,8 +76,9 @@ func (s *Service) RunDue(now time.Time) {
|
|||||||
}
|
}
|
||||||
if runtime.LastState == "Running" {
|
if runtime.LastState == "Running" {
|
||||||
// The job came due again while its own run is still in flight.
|
// The job came due again while its own run is still in flight.
|
||||||
// Apply the overlap policy and step past this occurrence.
|
// Apply the effective overlap policy and step past this
|
||||||
if queue {
|
// occurrence.
|
||||||
|
if s.effectiveOverlapPolicy(job) == domain.OverlapPolicyQueue {
|
||||||
runtime.Pending = true
|
runtime.Pending = true
|
||||||
}
|
}
|
||||||
s.advanceNextDueLocked(job, runtime, now)
|
s.advanceNextDueLocked(job, runtime, now)
|
||||||
@@ -165,6 +165,17 @@ func (s *Service) executeRun(ctx context.Context, jobCopy domain.Job, trigger st
|
|||||||
s.emit(JobChanged{JobID: jobCopy.ID})
|
s.emit(JobChanged{JobID: jobCopy.ID})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// effectiveOverlapPolicy resolves the overlap policy that actually governs a
|
||||||
|
// job: the job's own value when set, otherwise the global Config default. An
|
||||||
|
// empty Job.OverlapPolicy means "inherit the global default", which is why
|
||||||
|
// normalizeJobs leaves it empty rather than backfilling the configured value.
|
||||||
|
func (s *Service) effectiveOverlapPolicy(job *domain.Job) domain.OverlapPolicy {
|
||||||
|
if policy := domain.OverlapPolicy(strings.TrimSpace(job.OverlapPolicy)); policy != "" {
|
||||||
|
return policy
|
||||||
|
}
|
||||||
|
return s.store.Config.OverlapPolicy
|
||||||
|
}
|
||||||
|
|
||||||
// anyRunningLocked reports whether any loaded job is currently in the "Running"
|
// anyRunningLocked reports whether any loaded job is currently in the "Running"
|
||||||
// state. It backs the sequential-mode guards in RunNow and RunDue. The caller
|
// state. It backs the sequential-mode guards in RunNow and RunDue. The caller
|
||||||
// must hold mu.
|
// must hold mu.
|
||||||
|
|||||||
Reference in New Issue
Block a user