notify

package
v0.0.10 Latest Latest
Warning

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

Go to latest
Published: Sep 5, 2026 License: Apache-2.0 Imports: 19 Imported by: 0

Documentation

Overview

Package notify implements the Hub's Prometheus-backed daily report and idle-alert notification service, posted to Feishu and configured via the admin API. Config and runtime state (history, arm/disarm) persist in a single ConfigMap so ws-proxy restarts don't lose them.

Index

Constants

View Source
const (
	ResultSuccess = "success"
	ResultFailure = "failure"

	HistoryTypeDailyReport = "dailyReport"
	HistoryTypeIdleAlert   = "idleAlert"
)

Result / history type constants — shared between the scheduler and the admin API handlers.

View Source
const ScopeCombined = "combined"

ScopeCombined is the Scope value of the cross-cluster rollup entry, as opposed to the per-cluster entries which carry the cluster ID.

Variables

This section is empty.

Functions

This section is empty.

Types

type ClusterIdleStatus

type ClusterIdleStatus struct {
	ClusterID string
	Idle      bool
	Ok        bool
}

ClusterIdleStatus is the per-cluster idle-check outcome. Ok is false when the query failed or the cluster is unknown — the result must be treated as indeterminate and never as "idle".

type Config

type Config struct {
	DailyReport DailyReportConfig `json:"dailyReport"`
	IdleAlert   IdleAlertConfig   `json:"idleAlert"`
}

Config is the persisted notification configuration.

type DailyReportConfig

type DailyReportConfig struct {
	Enabled bool `json:"enabled"`
	// SendHourCST is the hour of day (0-23) in Asia/Shanghai the report is sent.
	SendHourCST int `json:"sendHourCST"`
}

DailyReportConfig controls the scheduled daily Feishu report.

type FeishuCard

type FeishuCard struct {
	Schema string         `json:"schema"`
	Header FeishuCardHead `json:"header"`
	Body   FeishuCardBody `json:"body"`
}

FeishuCard is a Feishu (Lark) interactive card, schema 2.0.

type FeishuCardBody

type FeishuCardBody struct {
	Elements []FeishuCardElement `json:"elements"`
}

FeishuCardBody holds the card's element list.

type FeishuCardColumn

type FeishuCardColumn struct {
	Tag             string              `json:"tag"`
	Width           string              `json:"width,omitempty"`
	Weight          int                 `json:"weight,omitempty"`
	VerticalAlign   string              `json:"vertical_align,omitempty"`
	BackgroundStyle string              `json:"background_style,omitempty"`
	Padding         string              `json:"padding,omitempty"`
	Elements        []FeishuCardElement `json:"elements,omitempty"`
}

FeishuCardColumn is one column within a column_set element.

type FeishuCardElement

type FeishuCardElement struct {
	Tag string `json:"tag"`

	// markdown
	Content   string `json:"content,omitempty"`
	TextAlign string `json:"text_align,omitempty"`

	// column_set
	HorizontalSpacing string             `json:"horizontal_spacing,omitempty"`
	FlexMode          string             `json:"flex_mode,omitempty"`
	Columns           []FeishuCardColumn `json:"columns,omitempty"`

	// collapsible_panel
	Expanded        bool                   `json:"expanded,omitempty"`
	Header          *FeishuCollapsibleHead `json:"header,omitempty"`
	Border          map[string]string      `json:"border,omitempty"`
	VerticalSpacing string                 `json:"vertical_spacing,omitempty"`
	Padding         string                 `json:"padding,omitempty"`
	Elements        []FeishuCardElement    `json:"elements,omitempty"`

	// chart (VChart)
	ChartSpec map[string]any `json:"chart_spec,omitempty"`
}

FeishuCardElement is one element within a Feishu interactive card body, or a column within a column_set. The tag determines which fields are used.

type FeishuCardHead

type FeishuCardHead struct {
	Title    FeishuCardElement `json:"title"`
	Template string            `json:"template"`
}

FeishuCardHead is the card header: title + accent color.

type FeishuCollapsibleHead

type FeishuCollapsibleHead struct {
	Title FeishuCardElement `json:"title"`
}

FeishuCollapsibleHead is the header of a collapsible_panel element.

type HistoryEntry

type HistoryEntry struct {
	Time time.Time `json:"time"`
	Type string    `json:"type"`
	// Result is "success" or "failure".
	Result string `json:"result"`
	Detail string `json:"detail,omitempty"`
}

HistoryEntry records the outcome of one daily-report or idle-alert run.

type IdleAlertConfig

type IdleAlertConfig struct {
	Enabled bool `json:"enabled"`
	// WatchedClusters are cluster IDs monitored for the idle condition. The
	// alert fires only when ALL of them are simultaneously idle.
	WatchedClusters []string `json:"watchedClusters"`
	// IdleThresholdMinutes is the minutes of zero sandbox-create activity
	// (any result) required to consider a cluster idle.
	IdleThresholdMinutes int `json:"idleThresholdMinutes"`
	// Armed is whether idle detection is currently active. Auto-disarmed
	// after firing once.
	Armed   bool       `json:"armed"`
	ArmedAt *time.Time `json:"armedAt,omitempty"`
}

IdleAlertConfig controls the idle-cluster alert.

type Params

type Params struct {
	Client           client.Client
	Namespace        string
	ConfigMapName    string
	PrometheusURL    string
	PrometheusToken  string
	FeishuWebhookURL string
	Clusters         *cluster.Store
}

Params configures a new Service.

type QuerySpec

type QuerySpec struct {
	Key         string
	Description string
	PromQL      string
}

QuerySpec is one named PromQL query making up a report.

type Report

type Report struct {
	GeneratedAt   time.Time
	PrometheusURL string
	Window        ReportWindow
	Clusters      []string
	Scopes        []ScopeReport
	// NoDataClusters lists cluster IDs whose per-cluster scope returned no
	// data at all for this window (e.g. a newly-added cluster with no
	// SandboxPool deployed yet). The card renders normally for every other
	// cluster and calls these out in a footer line instead of silently
	// omitting them.
	NoDataClusters []string
}

Report is the full daily-report payload: a combined scope across every cluster plus one scope per individual cluster.

type ReportWindow

type ReportWindow struct {
	Start   time.Time
	End     time.Time
	Seconds int64
	Literal string
}

ReportWindow describes the absolute time window a Report covers.

type Scalar

type Scalar = *float64

Scalar is a nullable metric value. nil means "n/a" — either the query legitimately returned no data, or (in the idle-check path) the query failed and the result must be treated as indeterminate.

type ScopeReport

type ScopeReport struct {
	Scope          string
	ClusterMatcher string
	Metrics        map[string]Scalar
	Derived        map[string]Scalar
	// HasData is false when every query in this scope returned no series at
	// all — the signature of a cluster with no SandboxPool deployed yet
	// rather than a cluster that is merely quiet. The daily report card must
	// call this out explicitly instead of rendering as if nothing happened.
	HasData bool
}

ScopeReport is one report scope: either the combined view across all clusters, or a single cluster.

type Service

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

Service is the notification service: it owns the persisted config + history ConfigMap, the Prometheus query engine, and the Feishu sender, and runs the daily-report and idle-alert background loops.

func New

func New(p Params) *Service

New constructs a Service. It performs no I/O.

func (*Service) ArmIdleAlert

func (s *Service) ArmIdleAlert(ctx context.Context) (Config, error)

ArmIdleAlert marks the idle alert as armed and returns the updated config.

func (*Service) DisarmIdleAlert

func (s *Service) DisarmIdleAlert(ctx context.Context) (Config, error)

DisarmIdleAlert marks the idle alert as disarmed and returns the updated config.

func (*Service) Enabled

func (s *Service) Enabled() bool

Enabled reports whether the service has enough configuration to do anything: a K8s client to persist state, and a metrics source to read.

func (*Service) LoadConfig

func (s *Service) LoadConfig(ctx context.Context) (Config, error)

LoadConfig returns the persisted config, or the default config if the ConfigMap (or the key within it) does not exist yet.

func (*Service) LoadHistory

func (s *Service) LoadHistory(ctx context.Context) ([]HistoryEntry, error)

LoadHistory returns the persisted history, most-recent last.

func (*Service) LoadState

func (s *Service) LoadState(ctx context.Context) (runtimeState, error)

LoadState returns the persisted scheduler state, zero-valued when absent.

func (*Service) Run

func (s *Service) Run(ctx context.Context)

Run starts the daily-report and idle-alert background loops. It blocks until ctx is canceled.

func (*Service) SaveState

func (s *Service) SaveState(ctx context.Context, st runtimeState) error

SaveState persists scheduler state, creating the ConfigMap if necessary.

func (*Service) SendDailyReportNow

func (s *Service) SendDailyReportNow(ctx context.Context, now time.Time)

SendDailyReportNow builds and sends a daily report on demand, for the admin "trigger now" API — the 24h window ends at now rather than waiting for the next scheduled tick.

func (*Service) UpdateConfig

func (s *Service) UpdateConfig(ctx context.Context, cfg Config) (Config, error)

UpdateConfig replaces the persisted config wholesale (PUT semantics) and returns what was actually stored.

type TimeSeriesPoint

type TimeSeriesPoint struct {
	Time  time.Time
	Value float64
}

TimeSeriesPoint is one sample of a range-query time series.

type UserCount

type UserCount struct {
	User  string
	Count float64
}

UserCount is one row of the daily report's top-creators ranking.

Jump to

Keyboard shortcuts

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