X-Git-Url: https://git.giacomolli.uk/onechat/blobdiff_plain/2124c559da8f164a43a3da987b399b6ac6125035..c781f79f3c8cb9a7577ee1574d196988da2719b3:/schedule.go?ds=inline diff --git a/schedule.go b/schedule.go index b3a65ea..5fa35da 100644 --- a/schedule.go +++ b/schedule.go @@ -33,10 +33,10 @@ const ( // scheduleSource is the source of the work events of the runs. scheduleSource = "schedule" - // scheduleCheck is the longest wait of Run before it looks at the times - // again, so that it sees a suspend of the machine or a change of the - // clock. - scheduleCheck = time.Minute + // scheduleClockWaitTimeout is the longest wait of Run before it looks + // at the times again, so that it sees a suspend of the machine or a + // change of the clock. + scheduleClockWaitTimeout = time.Minute // scheduleLate is how long after its time a run is late. scheduleLate = time.Minute @@ -48,6 +48,40 @@ const ( scheduleLateLine = "This run is late: the daemon was stopped at that time." ) +// Schedules holds the schedules of the agent: tasks that start a turn at one +// time or at the times of a cron expression. Each change writes the file whole +// before it returns, so a schedule survives a restart. The mutex protects the +// schedules, because the tools change them from a turn while Run reads them. +// changed tells Run that a set or a remove changed the times. +type Schedules struct { + path string + owner string + clock func() time.Time + logger *slog.Logger + changed chan struct{} + + mutex sync.Mutex + file ScheduleFile +} + +// ScheduleFile is the content of the file of the schedules: the ID of the last +// schedule, so that an ID is never used again, and the schedules. +type ScheduleFile struct { + Next int `json:"next"` + Schedules []Schedule `json:"schedules"` +} + +// Schedule is one schedule: its owner, its ID, the task for the agent, the cron +// expression of a repeating schedule, empty for a one-time schedule, and its +// next time. +type Schedule struct { + Owner string `json:"owner"` + ID int `json:"id"` + Text string `json:"text"` + Cron string `json:"cron"` + Due time.Time `json:"due"` +} + // openSchedules reads the schedules of the file at path. A missing file holds // none. The owner names its agent. Schedules without an owner take this name. A // different stored owner is an error. The clock gives the time and the time @@ -58,7 +92,6 @@ func openSchedules(path, owner string, clock func() time.Time, logger *slog.Logg owner: owner, clock: clock, logger: logger, - check: scheduleCheck, changed: make(chan struct{}, 1), } @@ -108,27 +141,11 @@ func openSchedules(path, owner string, clock func() time.Time, logger *slog.Logg return s, nil } -// Schedules holds the schedules of the agent: tasks that start a turn at one -// time or at the times of a cron expression. Each change writes the file whole -// before it returns, so a schedule survives a restart. The mutex protects the -// schedules, because the tools change them from a turn while Run reads them. -// changed tells Run that a set or a remove changed the times. -type Schedules struct { - path string - owner string - clock func() time.Time - logger *slog.Logger - check time.Duration - changed chan struct{} - - mutex sync.Mutex - file ScheduleFile -} - // Run starts the runs of the due schedules in l until ctx ends. It waits until -// the first due time, at most check at a time, and also wakes at a set or a -// remove. So a schedule that came due while the daemon was stopped runs at the -// start. It returns the error of a write of the log or of the file. +// the first due time, at most scheduleClockWaitTimeout at a time, and also +// wakes at a set or a remove. So a schedule that came due while the daemon was +// stopped runs at the start. It returns the error of a write of the log or of +// the file. func (s *Schedules) Run(ctx context.Context, l *TurnLoop) error { for { err := s.deliver(ctx, l) @@ -143,7 +160,7 @@ func (s *Schedules) Run(ctx context.Context, l *TurnLoop) error { wait, found := s.Wait(s.clock()) if found { - timer = time.NewTimer(min(wait, s.check)) + timer = time.NewTimer(min(wait, scheduleClockWaitTimeout)) timeout = timer.C } @@ -421,24 +438,6 @@ func (s *Schedules) save() error { return nil } -// ScheduleFile is the content of the file of the schedules: the ID of the last -// schedule, so that an ID is never used again, and the schedules. -type ScheduleFile struct { - Next int `json:"next"` - Schedules []Schedule `json:"schedules"` -} - -// Schedule is one schedule: its owner, its ID, the task for the agent, the cron -// expression of a repeating schedule, empty for a one-time schedule, and its -// next time. -type Schedule struct { - Owner string `json:"owner"` - ID int `json:"id"` - Text string `json:"text"` - Cron string `json:"cron"` - Due time.Time `json:"due"` -} - // Message returns the text of a run at now for the log, with the times in the // location of now. The first line starts with [Schedule ID] and gives the due // time and once or the cron expression. Then come the text, the line about a