From b9505e83ab2c3e5cb51da0a80c8bff041bb1ec00 Mon Sep 17 00:00:00 2001 From: mixeme Date: Wed, 24 Jun 2026 22:16:43 +0300 Subject: [PATCH] domain/config.go + app: persist global pause state across restarts (T4.1, T4.2) Add Config.Paused bool so the scheduler's paused flag survives a restart. SetGlobalPause now writes the flag into store.Config and calls SaveConfig; NewService seeds s.paused from Config.Paused before computing first next-run times, so jobs show "Scheduler paused" immediately at startup when paused. Also add Paused to the yamlConfig shadow struct to keep the direct conversion from domain.Config valid until the YAML import path is dropped in T6.3. Co-Authored-By: Claude Sonnet 4.6 --- src/app/operations.go | 6 +++++- src/app/service.go | 1 + src/domain/config.go | 1 + src/storage/store.go | 15 ++++++++------- 4 files changed, 15 insertions(+), 8 deletions(-) diff --git a/src/app/operations.go b/src/app/operations.go index e853f72..c0387fd 100644 --- a/src/app/operations.go +++ b/src/app/operations.go @@ -152,13 +152,17 @@ func (s *Service) SetEnabled(id int, enabled bool) error { func (s *Service) SetGlobalPause(paused bool) error { s.mu.Lock() s.paused = paused + s.store.Config.Paused = paused now := time.Now() for index := range s.jobs { job := &s.jobs[index] runtime := s.runtimeForLocked(job) s.refreshNextRunFromLocked(job, runtime, now) } - err := s.store.SaveJobs(s.jobs) + err := s.store.SaveConfig() + if err == nil { + err = s.store.SaveJobs(s.jobs) + } s.mu.Unlock() state, detail := "Resumed", "All job execution resumed" diff --git a/src/app/service.go b/src/app/service.go index 210ca66..33c7ff3 100644 --- a/src/app/service.go +++ b/src/app/service.go @@ -82,6 +82,7 @@ func NewService(store *storage.Store, jobs []domain.Job) *Service { schedules: make(map[int]domain.Schedule, len(jobs)), runJob: runner.RunJob, ctx: context.Background(), + paused: store.Config.Paused, } // Parse every schedule once, then compute each job's first next-run so the // Service is ready to schedule the moment it exists — mirroring the old diff --git a/src/domain/config.go b/src/domain/config.go index f0095ca..0cbfb3d 100644 --- a/src/domain/config.go +++ b/src/domain/config.go @@ -40,6 +40,7 @@ type Config struct { NotifyOnFailure bool `json:"notify_on_failure,omitempty"` ExecutionMode ExecutionMode `json:"execution_mode,omitempty"` OverlapPolicy OverlapPolicy `json:"overlap_policy,omitempty"` + Paused bool `json:"paused,omitempty"` } // JobsFile is the on-disk shape of jobs.json. Wrapping the slice in a top-level diff --git a/src/storage/store.go b/src/storage/store.go index 27cbbdd..2673bc0 100644 --- a/src/storage/store.go +++ b/src/storage/store.go @@ -24,15 +24,16 @@ 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"` + Paused bool `yaml:"paused,omitempty"` } type yamlJob struct {