Add cron jobs to service

This commit is contained in:
dwrz
2026-06-02 12:04:02 +00:00
parent e5238e4081
commit 6fb63c8c90
84 changed files with 3022 additions and 2452 deletions

View File

@@ -21,6 +21,7 @@ import (
"time"
"code.chimeric.al/chimerical/odidere/internal/config"
"code.chimeric.al/chimerical/odidere/internal/job"
"code.chimeric.al/chimerical/odidere/internal/llm"
"code.chimeric.al/chimerical/odidere/internal/service/templates"
"code.chimeric.al/chimerical/odidere/internal/stt"
@@ -28,6 +29,7 @@ import (
"code.chimeric.al/chimerical/odidere/internal/tts"
"github.com/google/uuid"
"github.com/robfig/cron/v3"
openai "github.com/sashabaranov/go-openai"
)
@@ -38,6 +40,8 @@ var static embed.FS
// It owns the HTTP server and all processing clients.
type Service struct {
cfg *config.Config
cron *cron.Cron
jobs []*job.Job
llm *llm.Client
log *slog.Logger
mux *http.ServeMux
@@ -85,6 +89,17 @@ func New(cfg *config.Config, log *slog.Logger) (*Service, error) {
}
svc.tts = ttsClient
// Convert job configs to jobs.
jobs := make([]*job.Job, 0, len(cfg.Jobs))
for _, jc := range cfg.Jobs {
j, err := job.New(jc, log, svc.llm)
if err != nil {
return nil, fmt.Errorf("create job %q: %w", jc.Name, err)
}
jobs = append(jobs, j)
}
svc.jobs = jobs
// Parse templates.
tmpl, err := templates.Parse()
if err != nil {
@@ -216,6 +231,10 @@ func (svc *Service) Run(ctx context.Context) error {
slog.String("url", svc.cfg.TTS.URL),
slog.String("default_voice", svc.cfg.TTS.Voice),
),
slog.Group(
"jobs",
slog.Int("count", svc.JobCount()),
),
slog.Any("shutdown_timeout", svc.cfg.GetShutdownTimeout()),
)
@@ -226,6 +245,47 @@ func (svc *Service) Run(ctx context.Context) error {
)
defer cancel()
// Register jobs with cron scheduler.
svc.cron = cron.New()
for _, j := range svc.jobs {
if !j.IsEnabled() {
svc.log.Info("job disabled", slog.String("name", j.Name()))
continue
}
entry, err := svc.cron.AddFunc(j.Schedule(), func() {
result := j.Run(ctx)
if result.Error != nil {
svc.log.Error("job failed",
slog.String("name", j.Name()),
slog.Any("error", result.Error),
slog.Duration(
"duration", result.Duration,
),
)
} else {
svc.log.Info("job completed",
slog.String("name", j.Name()),
slog.Duration(
"duration", result.Duration,
),
)
}
})
if err != nil {
svc.log.Error("failed to schedule job",
slog.String("name", j.Name()),
slog.Any("error", err),
)
continue
}
svc.log.Info("job scheduled",
slog.String("name", j.Name()),
slog.String("schedule", j.Schedule()),
slog.Int("entry_id", int(entry)),
)
}
svc.cron.Start()
// Start HTTP server in background.
var errs = make(chan error, 1)
go func() {
@@ -257,6 +317,10 @@ func (svc *Service) Run(ctx context.Context) error {
)
defer shutdownCancel()
// Stop cron scheduler — in-flight jobs continue to completion.
svc.log.Info("stopping job scheduler")
svc.cron.Stop()
svc.log.Info("shutting down HTTP server")
if err := svc.server.Shutdown(shutdownCtx); err != nil {
svc.log.Warn(
@@ -269,6 +333,16 @@ func (svc *Service) Run(ctx context.Context) error {
return nil
}
// ListJobs returns all registered jobs.
func (svc *Service) ListJobs() []*job.Job {
return svc.jobs
}
// JobCount returns the number of registered jobs.
func (svc *Service) JobCount() int {
return len(svc.jobs)
}
func (svc *Service) home(w http.ResponseWriter, r *http.Request) {
var (
ctx = r.Context()