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:
@@ -53,10 +53,11 @@ type Config struct {
|
||||
NotifyOnFailure bool `json:"notify_on_failure,omitempty"`
|
||||
ExecutionMode ExecutionMode `json:"execution_mode,omitempty"`
|
||||
OverlapPolicy OverlapPolicy `json:"overlap_policy,omitempty"`
|
||||
// DefaultTimeoutSeconds is the run timeout applied to jobs that do not set
|
||||
// their own Job.TimeoutSeconds. 0 (the default) means no timeout: such jobs
|
||||
// run to completion however long that takes.
|
||||
DefaultTimeoutSeconds int `json:"default_timeout_seconds,omitempty"`
|
||||
// DefaultTimeoutSeconds is the run timeout applied to jobs that leave their
|
||||
// own Job.TimeoutSeconds unset. 0 (the default) means no timeout: such jobs
|
||||
// run to completion however long that takes. It is written even when 0 —
|
||||
// omitempty would hide a deliberate choice from the hand-editable config.
|
||||
DefaultTimeoutSeconds int `json:"default_timeout_seconds"`
|
||||
Paused bool `json:"paused,omitempty"`
|
||||
// Theme selects the visual appearance. Empty is treated as ThemeDefault so
|
||||
// configs written before this field existed keep the original look.
|
||||
|
||||
+15
-5
@@ -15,9 +15,19 @@ type Job struct {
|
||||
StartOnly bool `json:"start_only,omitempty"`
|
||||
Enabled bool `json:"enabled"`
|
||||
OverlapPolicy string `json:"overlap_policy,omitempty"`
|
||||
// TimeoutSeconds bounds how long a run may take before it is killed. 0 means
|
||||
// "inherit the global Config.DefaultTimeoutSeconds", mirroring OverlapPolicy:
|
||||
// normalizeJobs must leave 0 untouched rather than backfilling the default.
|
||||
// The inherited global default may itself be 0, meaning no timeout at all.
|
||||
TimeoutSeconds int `json:"timeout_seconds,omitempty"`
|
||||
// TimeoutSeconds bounds how long a run may take before it is killed. It is a
|
||||
// pointer so the three states stay distinguishable on disk: absent (nil)
|
||||
// means "inherit the global Config.DefaultTimeoutSeconds", mirroring
|
||||
// OverlapPolicy's empty string; an explicit 0 means "no timeout" and does
|
||||
// not inherit; a positive value is the per-job limit in seconds. The
|
||||
// inherited global default may itself be 0, also meaning no timeout.
|
||||
// normalizeJobs must leave nil untouched rather than backfilling a value.
|
||||
TimeoutSeconds *int `json:"timeout_seconds,omitempty"`
|
||||
}
|
||||
|
||||
// TimeoutSecondsPtr returns a pointer suitable for Job.TimeoutSeconds. It exists
|
||||
// because nil (inherit) and an explicit 0 (no timeout) are different states, so
|
||||
// callers cannot just assign an int.
|
||||
func TimeoutSecondsPtr(seconds int) *int {
|
||||
return &seconds
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user