mirror of
https://github.com/tiennm99/claude-code-routine-cron.git
synced 2026-05-24 02:24:22 +00:00
61 lines
1.6 KiB
Go
61 lines
1.6 KiB
Go
package main
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"log/slog"
|
|
|
|
"github.com/robfig/cron/v3"
|
|
)
|
|
|
|
// Scheduler wires cron schedules to FireClient invocations.
|
|
type Scheduler struct {
|
|
cron *cron.Cron
|
|
fire *FireClient
|
|
log *slog.Logger
|
|
}
|
|
|
|
// NewScheduler builds a Scheduler with all schedules registered. Returns an
|
|
// error if any registration fails (defensive — config.go already validates
|
|
// expressions, but the cron library may have stricter rules at AddFunc time).
|
|
func NewScheduler(cfg *Config, fire *FireClient, log *slog.Logger) (*Scheduler, error) {
|
|
c := cron.New(cron.WithLocation(cfg.Location))
|
|
s := &Scheduler{cron: c, fire: fire, log: log}
|
|
|
|
for _, expr := range cfg.Schedules {
|
|
expr := expr
|
|
_, err := c.AddFunc(expr, func() {
|
|
ctx, cancel := context.WithTimeout(context.Background(), httpFireTimeout)
|
|
defer cancel()
|
|
if err := fire.Fire(ctx, expr); err != nil {
|
|
log.Error("fire returned error", "cron", expr, "err", err.Error())
|
|
}
|
|
})
|
|
if err != nil {
|
|
return nil, fmt.Errorf("register cron %q: %w", expr, err)
|
|
}
|
|
}
|
|
return s, nil
|
|
}
|
|
|
|
// Start the underlying cron scheduler. Non-blocking.
|
|
func (s *Scheduler) Start() {
|
|
s.cron.Start()
|
|
}
|
|
|
|
// Stop the scheduler and wait for in-flight tasks to finish or for the
|
|
// supplied context to be cancelled, whichever comes first.
|
|
func (s *Scheduler) Stop(ctx context.Context) {
|
|
stopped := s.cron.Stop().Done()
|
|
select {
|
|
case <-stopped:
|
|
case <-ctx.Done():
|
|
s.log.Warn("shutdown deadline reached before all fires completed")
|
|
}
|
|
}
|
|
|
|
// EntryCount exposes the number of registered schedules for tests/diagnostics.
|
|
func (s *Scheduler) EntryCount() int {
|
|
return len(s.cron.Entries())
|
|
}
|