81 lines
2.1 KiB
Go
81 lines
2.1 KiB
Go
package selftest
|
||
|
||
import (
|
||
"context"
|
||
"database/sql"
|
||
"fmt"
|
||
"time"
|
||
|
||
"weatherstation/internal/database"
|
||
)
|
||
|
||
// Run 执行启动前自检
|
||
// 1) 数据库可用 2) 关键表存在 3) 基础查询可执行
|
||
func Run(ctx context.Context) error {
|
||
db := database.GetDB()
|
||
if err := pingDB(ctx, db); err != nil {
|
||
return fmt.Errorf("数据库连通性失败: %w", err)
|
||
}
|
||
if err := ensureTables(ctx, db); err != nil {
|
||
return fmt.Errorf("关键表缺失: %w", err)
|
||
}
|
||
if err := basicQuery(ctx, db); err != nil {
|
||
return fmt.Errorf("基础查询失败: %w", err)
|
||
}
|
||
return nil
|
||
}
|
||
|
||
func pingDB(ctx context.Context, db *sql.DB) error {
|
||
ctx, cancel := context.WithTimeout(ctx, 3*time.Second)
|
||
defer cancel()
|
||
return db.PingContext(ctx)
|
||
}
|
||
|
||
func ensureTables(ctx context.Context, db *sql.DB) error {
|
||
required := []string{
|
||
"public.stations",
|
||
"public.rs485_weather_data",
|
||
"public.rs485_weather_10min",
|
||
"public.forecast_hourly",
|
||
}
|
||
for _, t := range required {
|
||
var exists bool
|
||
if err := db.QueryRowContext(ctx, "SELECT to_regclass($1) IS NOT NULL", t).Scan(&exists); err != nil {
|
||
return err
|
||
}
|
||
if !exists {
|
||
return fmt.Errorf("缺少表: %s", t)
|
||
}
|
||
}
|
||
return nil
|
||
}
|
||
|
||
func basicQuery(ctx context.Context, db *sql.DB) error {
|
||
// 若无站点则跳过后续测试
|
||
var stationID string
|
||
_ = db.QueryRowContext(ctx, "SELECT station_id FROM stations LIMIT 1").Scan(&stationID)
|
||
|
||
// 10分钟表可被查询(允许为空)
|
||
var cnt int
|
||
if err := db.QueryRowContext(ctx, "SELECT COUNT(*) FROM rs485_weather_10min").Scan(&cnt); err != nil {
|
||
return err
|
||
}
|
||
|
||
// 若有站点,做一次安全时间窗聚合验证(不要求有数据,只要语句可执行)
|
||
if stationID != "" {
|
||
from := time.Now().Add(-2 * time.Hour).Truncate(time.Hour)
|
||
to := time.Now().Truncate(time.Hour)
|
||
_, err := db.QueryContext(ctx,
|
||
`WITH base AS (
|
||
SELECT * FROM rs485_weather_10min WHERE station_id=$1 AND bucket_start >= $2 AND bucket_start <= $3
|
||
), g AS (
|
||
SELECT date_trunc('hour', bucket_start) AS grp, SUM(sample_count) AS n_sum FROM base GROUP BY 1
|
||
) SELECT COUNT(*) FROM g`, stationID, from, to,
|
||
)
|
||
if err != nil {
|
||
return err
|
||
}
|
||
}
|
||
return nil
|
||
}
|