Documentation
¶
Index ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type AddHeartbeatRequest ¶
type DeleteHeartbeatRequest ¶
type DeleteHeartbeatRequest struct {
ID string `json:"id" jsonschema:"The unique ID of the heartbeat to delete."`
}
type Heartbeat ¶
type HeartbeatIDSelector ¶
type HeartbeatIDSelector string
HeartbeatIDSelector selects a single heartbeat by ID for get/update/delete operations.
type HeartbeatList ¶
type HeartbeatList struct {
Heartbeats []*Heartbeat `json:"body,omitempty"`
}
HeartbeatList is a pg.Reader that accumulates scanned heartbeat rows.
type HeartbeatListRequest ¶
type HeartbeatListRequest struct {
Fired *bool `json:"fired,omitempty"`
}
HeartbeatListRequest is the request type for listing heartbeats.
type HeartbeatMarkFiredSelector ¶
type HeartbeatMarkFiredSelector string
HeartbeatMarkFiredSelector selects a heartbeat by ID for the mark-fired UPDATE.
type HeartbeatMeta ¶
type ListHeartbeatsRequest ¶
type ListHeartbeatsRequest struct {
IncludeFired bool `json:"include_fired,omitempty" jsonschema:"Include already-fired heartbeats."`
}
type Store ¶
type Store interface {
// Create persists a new heartbeat with the given metadata and returns it.
Create(ctx context.Context, meta HeartbeatMeta) (*Heartbeat, error)
// Get retrieves a heartbeat by its unique identifier.
Get(ctx context.Context, id string) (*Heartbeat, error)
// Delete removes a heartbeat by its unique identifier and returns it.
Delete(ctx context.Context, id string) (*Heartbeat, error)
// List returns all heartbeats. If includeFired is true, includes heartbeats
// that have already fired; otherwise only pending heartbeats are returned.
List(ctx context.Context, includeFired bool) ([]*Heartbeat, error)
// Update modifies an existing heartbeat's metadata and returns the updated record.
Update(ctx context.Context, id string, meta HeartbeatMeta) (*Heartbeat, error)
// Next returns heartbeats that are due to fire (i.e., their scheduled time
// has arrived or passed and they have not yet fired).
Next(ctx context.Context) ([]*Heartbeat, error)
}
Store is the interface for a heartbeat store, providing CRUD operations and scheduling queries for heartbeat records.
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 ¶
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) IsZero ¶
IsZero returns true if ts has no constraints and no explicit timezone. A spec with an explicit Loc (even with wildcard fields) is not zero, so that timezone-only updates are treated as schedule changes.
func (TimeSpec) MarshalJSON ¶
MarshalJSON serialises TimeSpec as {"schedule":"...","timezone":"..."} (timezone field omitted when UTC/unset), preserving all information through a round-trip.
func (TimeSpec) Next ¶
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 ¶
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 ¶
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 */
}