heartbeat

package
v0.4.2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Mar 10, 2026 License: Apache-2.0 Imports: 15 Imported by: 0

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type AddHeartbeatRequest

type AddHeartbeatRequest struct {
	Message  string `json:"message"            jsonschema:"Short reminder message to deliver when the heartbeat matures."`
	Schedule string `` /* 178-byte string literal not displayed */
	Timezone string `` /* 248-byte string literal not displayed */
}

type DeleteHeartbeatRequest

type DeleteHeartbeatRequest struct {
	ID string `json:"id" jsonschema:"The unique ID of the heartbeat to delete."`
}

type Heartbeat

type Heartbeat struct {
	ID        string     `json:"id"`
	Message   string     `json:"message"`
	Schedule  TimeSpec   `json:"schedule"`
	Fired     bool       `json:"fired,omitempty"`
	LastFired *time.Time `json:"last_fired,omitempty"`
	Created   time.Time  `json:"created"`
	Modified  time.Time  `json:"modified"`
}

type ListHeartbeatsRequest

type ListHeartbeatsRequest struct {
	IncludeFired bool `json:"include_fired,omitempty" jsonschema:"Include already-fired heartbeats."`
}

type Manager

type Manager struct {
	// contains filtered or unexported fields
}

Manager owns a Store and runs a background loop that fires due heartbeats. Create one with New, register an OnFire callback, then call Run in a goroutine.

func New

func New(store *Store, opts ...Opt) (*Manager, error)

New creates a Manager backed by the given store.

func (*Manager) ListPrompts

func (m *Manager) ListPrompts(_ context.Context) ([]llm.Prompt, error)

ListPrompts returns nil and satisfies the llm.Connector interface.

func (*Manager) ListResources

func (m *Manager) ListResources(_ context.Context) ([]llm.Resource, error)

ListResources returns nil and satisfies the llm.Connector interface.

func (*Manager) ListTools

func (m *Manager) ListTools(_ context.Context) ([]llm.Tool, error)

ListTools returns the heartbeat tools and satisfies the llm.Connector interface.

func (*Manager) Run

func (m *Manager) Run(ctx context.Context) error

Run starts the maturity-check loop and blocks until ctx is cancelled. It returns nil when ctx is done and satisfies the llm.Connector interface.

type Opt

type Opt func(*Manager) error

Opt is a functional option for configuring a Manager.

func WithLogger

func WithLogger(l *slog.Logger) Opt

WithLogger sets the logger used for error reporting inside the run loop.

func WithOnFire

func WithOnFire(fn func(context.Context, *Heartbeat)) Opt

WithOnFire registers a callback invoked for each heartbeat as it matures. Only one callback can be active; later calls overwrite earlier ones.

func WithPollInterval

func WithPollInterval(d time.Duration) Opt

WithPollInterval sets how often the Manager polls for due heartbeats. The default is 10 s.

type Store

type Store struct {
	// contains filtered or unexported fields
}

Store is a file-backed, concurrency-safe store for Heartbeat records. Each heartbeat is persisted as {id}.json inside the configured directory.

func NewStore

func NewStore(dir string) (*Store, error)

NewStore creates a new file-backed heartbeat store rooted at dir. The directory is created if it does not already exist.

func (*Store) Create

func (s *Store) Create(message string, schedule TimeSpec) (*Heartbeat, error)

Create persists a new Heartbeat derived from the supplied fields. A unique ID and timestamps are assigned automatically.

func (*Store) Delete

func (s *Store) Delete(id string) error

Delete removes the heartbeat file for the given ID. Returns ErrNotFound if no such heartbeat exists.

func (*Store) Due

func (s *Store) Due() ([]*Heartbeat, error)

Due returns all heartbeats whose next scheduled time is ≤ now and that have not yet fired.

func (*Store) Get

func (s *Store) Get(id string) (*Heartbeat, error)

Get retrieves a single Heartbeat by ID. Returns ErrNotFound if absent.

func (*Store) List

func (s *Store) List(includeFired bool) ([]*Heartbeat, error)

List returns all heartbeats in the store. When includeFired is false, already-fired heartbeats are excluded.

func (*Store) MarkFired

func (s *Store) MarkFired(id string) error

MarkFired sets Fired=true on the heartbeat and persists it.

func (*Store) Update

func (s *Store) Update(id, message string, schedule *TimeSpec) (*Heartbeat, error)

Update applies non-zero fields from message and schedule to the heartbeat identified by id. A non-nil schedule replaces the existing one and resets the Fired flag; nil schedule leaves it unchanged.

type TimeSpec

type TimeSpec struct {
	// Year constrains the four-digit calendar year (e.g. 2026). nil = any year.
	Year *int `json:"year,omitempty"`

	// Month constrains the month as numbers 1–12. Empty = any month.
	Month []int `json:"month,omitempty"`

	// Day constrains the day-of-month 1–31. Empty = any day.
	Day []int `json:"day,omitempty"`

	// Weekday constrains the day-of-week: 0 = Sunday … 6 = Saturday. Empty = any.
	Weekday []int `json:"weekday,omitempty"`

	// Hour constrains the hour 0–23. Empty = any hour.
	Hour []int `json:"hour,omitempty"`

	// Minute constrains the minute 0–59. Empty = any minute.
	Minute []int `json:"minute,omitempty"`

	// Loc is the timezone used when evaluating Next. nil means UTC.
	Loc *time.Location `json:"-"`
}

TimeSpec describes a recurring or one-shot schedule using cron-like fields. Each slice field constrains the schedule to the listed values; an empty slice means "any value matches" (wildcard). Multiple values in a slice are treated as OR — the time only needs to match one of them. TimeSpec.Next returns the earliest matching moment on or after a given time.

func NewTimeSpec

func NewTimeSpec[T time.Time | string](v T, loc *time.Location) (TimeSpec, error)

NewTimeSpec creates a TimeSpec from either a time.Time (one-shot, all fields pinned) or a cron string (5-field: "minute hour day month weekday"). loc is the timezone used when evaluating Next; nil means UTC.

Cron field syntax per field:

  • — any value (wildcard) n — exact value n,m,... — list of values n-m — inclusive range */step — every step-th value across the full range n-m/step — every step-th value within n–m

Examples:

NewTimeSpec[time.Time](t, nil)                        → one-shot at the exact minute of t (UTC)
NewTimeSpec[string]("0 9 * * 1-5", nil)               → 09:00 every weekday UTC
NewTimeSpec[string]("0 9 * * 1-5", londonLoc)         → 09:00 every weekday London time
NewTimeSpec[string]("*/15 * * * *", nil)               → every 15 minutes
NewTimeSpec[string]("30 14 15 6 * 2030", nil)          → 14:30 on 15 June 2030 (6-field, pinned year)

func (TimeSpec) MarshalJSON

func (ts TimeSpec) MarshalJSON() ([]byte, error)

MarshalJSON serialises TimeSpec as {"schedule":"...","timezone":"..."} (timezone field omitted when UTC/unset), preserving all information through a round-trip.

func (TimeSpec) Next

func (ts TimeSpec) Next(from time.Time) time.Time

Next returns the earliest time on or after from that satisfies every field of ts. The returned time is expressed in ts.Loc (UTC if nil). Returns the zero time.Time when no match exists within a four-year window (e.g. an impossible Day+Weekday combination).

func (TimeSpec) String

func (ts TimeSpec) String() string

String returns the cron expression for this TimeSpec. Recurring schedules produce a 5-field expression: "minute hour day-of-month month day-of-week". One-shot schedules with a pinned year produce a 6-field expression: "minute hour day-of-month month day-of-week year".

func (*TimeSpec) UnmarshalJSON

func (ts *TimeSpec) UnmarshalJSON(data []byte) error

UnmarshalJSON accepts the canonical {"schedule":"...","timezone":"..."} envelope. For backward-compatibility it also accepts a bare cron/RFC3339 string.

Note: unlike NewTimeSpec, this does NOT validate that the schedule has a future occurrence. Stored heartbeats must survive round-trips even after their scheduled time has passed (e.g. a fired one-shot).

type UpdateHeartbeatRequest

type UpdateHeartbeatRequest struct {
	ID       string `json:"id"                 jsonschema:"The unique ID of the heartbeat to update."`
	Message  string `json:"message,omitempty"  jsonschema:"New message; empty keeps existing."`
	Schedule string `json:"schedule,omitempty" jsonschema:"New schedule (RFC 3339 timestamp or 5-field cron expression); empty keeps existing."`
	Timezone string `` /* 225-byte string literal not displayed */
}

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL