Add the scheduler core with period keys and catch-up
CI / ci (push) Successful in 8m22s
CI / ci (pull_request) Successful in 8m2s

internal/scheduler runs registered schedules (a name, a daily or weekly
rule read from the household settings, and a run function) in the
household zone with an injectable clock. Each fire time's period is
claimed by inserting schedule_runs(schedule, period_key) with ON
CONFLICT DO NOTHING, so a period runs at most once across restarts and
instances. At boot only each schedule's most recent fire time is
considered: within 24 h it runs once, older it is claimed as missed so
it never runs later. Settings changes move the next fire time through
SettingsService.Subscribe. DST follows household.LocalTime. The server
starts it with the worker context and waits for it before closing the
database; the concrete schedules come in later Feature 20 tasks.

Maestro task f7024755-c3d3-46f3-b798-e242ad676c1e.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-09 18:17:41 -04:00
co-authored by Claude Opus 5.5
parent dcd35e78ec
commit b46192a43d
8 changed files with 1239 additions and 2 deletions
+3
View File
@@ -24,6 +24,9 @@ type Querier interface {
// Marks the oldest queued job running and returns it. Returns sql.ErrNoRows
// when no job is queued.
ClaimNextJob(ctx context.Context, now sql.NullString) (Job, error)
// Claims one period of a schedule. The insert is the claim: 1 row means
// this caller owns the period, 0 rows means it was already claimed.
ClaimScheduleRun(ctx context.Context, arg ClaimScheduleRunParams) (int64, error)
// Clears every day's calendar event id: none is on the chosen calendar.
ClearCalendarEvents(ctx context.Context, updatedAt string) error
// Records that Google refuses the stored grant: clears the refresh token and
+38
View File
@@ -0,0 +1,38 @@
// Code generated by sqlc. DO NOT EDIT.
// versions:
// sqlc v1.31.1
// source: schedule_runs.sql
package db
import (
"context"
)
const claimScheduleRun = `-- name: ClaimScheduleRun :execrows
INSERT INTO schedule_runs (id, schedule, period_key, created_at)
VALUES (?, ?, ?, ?)
ON CONFLICT (schedule, period_key) DO NOTHING
`
type ClaimScheduleRunParams struct {
ID string
Schedule string
PeriodKey string
CreatedAt string
}
// Claims one period of a schedule. The insert is the claim: 1 row means
// this caller owns the period, 0 rows means it was already claimed.
func (q *Queries) ClaimScheduleRun(ctx context.Context, arg ClaimScheduleRunParams) (int64, error) {
result, err := q.db.ExecContext(ctx, claimScheduleRun,
arg.ID,
arg.Schedule,
arg.PeriodKey,
arg.CreatedAt,
)
if err != nil {
return 0, err
}
return result.RowsAffected()
}