feat: make per-job timeout 0 mean "no timeout" instead of inherit

A per-job timeout now has three distinct states: unset inherits the global
default, an explicit 0 means no timeout and does not inherit, and a positive
value is the per-job limit. Job.TimeoutSeconds became *int so unset and 0 stay
distinguishable in jobs.json.

Also fixes the global default, which could not persist a 0. loadOrCreateConfig
normalized DefaultTimeoutSeconds <= 0 back to 30 on every read of an existing
gosentry.json, so "no timeout" only held until the next restart. The field is
now written unconditionally (no omitempty) and read back as-is.

Existing jobs and configs are unaffected: a job with no timeout_seconds still
inherits, and a saved global default of 30 stays 30.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
mixeme
2026-07-26 22:02:46 +03:00
parent 7f4f63eb8e
commit e85cbc4eb1
14 changed files with 167 additions and 47 deletions
+2 -2
View File
@@ -367,8 +367,8 @@ func validateJob(job domain.Job) error {
if policy != "" && policy != string(domain.OverlapPolicySkip) && policy != string(domain.OverlapPolicyQueue) {
return errors.New("overlap policy must be 'skip', 'queue', or empty")
}
if job.TimeoutSeconds < 0 {
return errors.New("timeout must be zero (inherit) or a positive number of seconds")
if job.TimeoutSeconds != nil && *job.TimeoutSeconds < 0 {
return errors.New("timeout must be zero (no timeout) or a positive number of seconds, or unset to inherit the global default")
}
return nil
}