P3.1: Add ExecutionMode/OverlapPolicy to Config; add Pending to JobRuntime
Introduces ExecutionMode (parallel/sequential) and OverlapPolicy (skip/queue) types and constants in domain/config.go, wires defaults (parallel/skip) into loadOrCreateConfig and the normalization pass, and adds validation in validateConfig. Adds Pending bool to JobRuntime as the flag P3.3 will use to re-run a queued overlap. Marks P3.1 done. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -476,5 +476,11 @@ func validateConfig(config domain.Config) error {
|
||||
if config.MaxLogAgeDays <= 0 {
|
||||
return errors.New("max log age days must be a positive number")
|
||||
}
|
||||
if config.ExecutionMode != domain.ExecutionModeParallel && config.ExecutionMode != domain.ExecutionModeSequential {
|
||||
return errors.New("execution mode must be 'parallel' or 'sequential'")
|
||||
}
|
||||
if config.OverlapPolicy != domain.OverlapPolicySkip && config.OverlapPolicy != domain.OverlapPolicyQueue {
|
||||
return errors.New("overlap policy must be 'skip' or 'queue'")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@ func newTempService(t *testing.T, jobs []domain.Job) *Service {
|
||||
JobsPath: filepath.Join(dir, "jobs.json"),
|
||||
LogsDir: filepath.Join(dir, "logs"),
|
||||
},
|
||||
Config: domain.Config{JobsDir: ".", LogsDir: "logs", MaxLogFiles: 100, MaxLogAgeDays: 30},
|
||||
Config: domain.Config{JobsDir: ".", LogsDir: "logs", MaxLogFiles: 100, MaxLogAgeDays: 30, ExecutionMode: domain.ExecutionModeParallel, OverlapPolicy: domain.OverlapPolicySkip},
|
||||
}
|
||||
return NewService(store, jobs)
|
||||
}
|
||||
|
||||
+31
-7
@@ -5,17 +5,41 @@ package domain
|
||||
// launches omit this flag and open the normal window.
|
||||
const StartInTrayArgument = "--start-in-tray"
|
||||
|
||||
// ExecutionMode controls whether due jobs run concurrently or one at a time.
|
||||
type ExecutionMode string
|
||||
|
||||
const (
|
||||
// ExecutionModeParallel allows all due jobs to start simultaneously.
|
||||
ExecutionModeParallel ExecutionMode = "parallel"
|
||||
// ExecutionModeSequential runs due jobs one after another, in order.
|
||||
ExecutionModeSequential ExecutionMode = "sequential"
|
||||
)
|
||||
|
||||
// OverlapPolicy decides what happens when a job's next run fires while the
|
||||
// previous run is still active.
|
||||
type OverlapPolicy string
|
||||
|
||||
const (
|
||||
// OverlapPolicySkip discards the new run when the job is already running.
|
||||
OverlapPolicySkip OverlapPolicy = "skip"
|
||||
// OverlapPolicyQueue holds the new run and starts it as soon as the current
|
||||
// run finishes.
|
||||
OverlapPolicyQueue OverlapPolicy = "queue"
|
||||
)
|
||||
|
||||
// Config is stored in gosentry.json next to the program. It contains only
|
||||
// application-level choices: where to read jobs from, where to write logs, and
|
||||
// how the desktop shell should behave.
|
||||
type Config struct {
|
||||
JobsDir string `json:"jobs_dir"`
|
||||
LogsDir string `json:"logs_dir"`
|
||||
MaxLogFiles int `json:"max_log_files"`
|
||||
MaxLogAgeDays int `json:"max_log_age_days"`
|
||||
StartOnLogin bool `json:"start_on_login,omitempty"`
|
||||
KeepRunningInTray bool `json:"keep_running_in_tray,omitempty"`
|
||||
NotifyOnFailure bool `json:"notify_on_failure,omitempty"`
|
||||
JobsDir string `json:"jobs_dir"`
|
||||
LogsDir string `json:"logs_dir"`
|
||||
MaxLogFiles int `json:"max_log_files"`
|
||||
MaxLogAgeDays int `json:"max_log_age_days"`
|
||||
StartOnLogin bool `json:"start_on_login,omitempty"`
|
||||
KeepRunningInTray bool `json:"keep_running_in_tray,omitempty"`
|
||||
NotifyOnFailure bool `json:"notify_on_failure,omitempty"`
|
||||
ExecutionMode ExecutionMode `json:"execution_mode,omitempty"`
|
||||
OverlapPolicy OverlapPolicy `json:"overlap_policy,omitempty"`
|
||||
}
|
||||
|
||||
// JobsFile is the on-disk shape of jobs.json. Wrapping the slice in a top-level
|
||||
|
||||
@@ -18,6 +18,10 @@ type JobRuntime struct {
|
||||
// scheduler comparisons. NextRun above is its formatted display string and is
|
||||
// the only form shown in the GUI.
|
||||
NextDue time.Time
|
||||
|
||||
// Pending is set when a run was skipped due to the overlap policy being
|
||||
// "queue". The scheduler will start this job as soon as the current run ends.
|
||||
Pending bool
|
||||
}
|
||||
|
||||
// NewRuntime builds the initial runtime state for a freshly loaded or created
|
||||
|
||||
+17
-7
@@ -24,13 +24,15 @@ type Store struct {
|
||||
// domain struct so the value conversions in importYAMLConfig / importYAMLJobs
|
||||
// remain valid.
|
||||
type yamlConfig struct {
|
||||
JobsDir string `yaml:"jobs_dir"`
|
||||
LogsDir string `yaml:"logs_dir"`
|
||||
MaxLogFiles int `yaml:"max_log_files"`
|
||||
MaxLogAgeDays int `yaml:"max_log_age_days"`
|
||||
StartOnLogin bool `yaml:"start_on_login,omitempty"`
|
||||
KeepRunningInTray bool `yaml:"keep_running_in_tray,omitempty"`
|
||||
NotifyOnFailure bool `yaml:"notify_on_failure,omitempty"`
|
||||
JobsDir string `yaml:"jobs_dir"`
|
||||
LogsDir string `yaml:"logs_dir"`
|
||||
MaxLogFiles int `yaml:"max_log_files"`
|
||||
MaxLogAgeDays int `yaml:"max_log_age_days"`
|
||||
StartOnLogin bool `yaml:"start_on_login,omitempty"`
|
||||
KeepRunningInTray bool `yaml:"keep_running_in_tray,omitempty"`
|
||||
NotifyOnFailure bool `yaml:"notify_on_failure,omitempty"`
|
||||
ExecutionMode domain.ExecutionMode `yaml:"execution_mode,omitempty"`
|
||||
OverlapPolicy domain.OverlapPolicy `yaml:"overlap_policy,omitempty"`
|
||||
}
|
||||
|
||||
type yamlJob struct {
|
||||
@@ -108,6 +110,8 @@ func loadOrCreateConfig(paths Paths) (domain.Config, error) {
|
||||
StartOnLogin: false,
|
||||
KeepRunningInTray: true,
|
||||
NotifyOnFailure: true,
|
||||
ExecutionMode: domain.ExecutionModeParallel,
|
||||
OverlapPolicy: domain.OverlapPolicySkip,
|
||||
}
|
||||
|
||||
if _, err := os.Stat(paths.ConfigPath); errors.Is(err, os.ErrNotExist) {
|
||||
@@ -147,6 +151,12 @@ func loadOrCreateConfig(paths Paths) (domain.Config, error) {
|
||||
if config.MaxLogAgeDays <= 0 {
|
||||
config.MaxLogAgeDays = 30
|
||||
}
|
||||
if config.ExecutionMode == "" {
|
||||
config.ExecutionMode = domain.ExecutionModeParallel
|
||||
}
|
||||
if config.OverlapPolicy == "" {
|
||||
config.OverlapPolicy = domain.OverlapPolicySkip
|
||||
}
|
||||
return config, nil
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user