Files
sundynix-agentix/sundynix-gateway/internal/store/pgsql.go
T
Blizzard e5fa0ae36c feat: Gateway store 桩换真实 GORM/Postgres + go-redis (含自动迁移与优雅降级)
第 2 层网关持久层落地,遵守 sundynix_ 表名前缀 + AutoMigrate 约定。

- store: GORM(NamingStrategy 前缀 sundynix_/单数) → User=sundynix_user, Task=sundynix_task
  启动 AutoMigrate;go-redis/v9 滑动窗口限流(Incr+Expire,按 IP)
- 优雅降级:连不上库则 warn 继续(不 fatal),保证无 Docker 的 make demo 仍跑通
- handler: SubmitTask 持久化任务(best-effort),Billing 真实读库返回 tasks_submitted
- main: OpenPostgres/OpenRedis 读 POSTGRES_DSN/REDIS_ADDR 环境变量
- 验证: 4 模块 build ✓;e2e 3 测试 PASS;live 双路径(真实库持久化 + 坏DSN降级)实测通过

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-10 11:43:53 +08:00

71 lines
2.1 KiB
Go

// Package store 封装 MainDB(PgSQL) 与 CacheDB(Redis) 的访问。
package store
import (
"context"
"log"
"gorm.io/driver/postgres"
"gorm.io/gorm"
"gorm.io/gorm/schema"
)
// Postgres 持有 MainDB 连接(Users / Billing / DSL)。
// db 为 nil 表示降级模式(连接失败时仍允许网关启动)。
type Postgres struct {
db *gorm.DB
}
// OpenPostgres 用 GORM 连接 MainDB 并自动迁移表结构。
// 表名统一 sundynix_ 前缀 + 单数(User→sundynix_user, Task→sundynix_task)。
// 连接失败不 fatal:返回降级实例,网关仍可启动(无 Docker 跑 demo 时即此路径)。
func OpenPostgres(dsn string) *Postgres {
db, err := gorm.Open(postgres.New(postgres.Config{DSN: dsn}), &gorm.Config{
NamingStrategy: schema.NamingStrategy{
TablePrefix: "sundynix_", // 所有表加前缀
SingularTable: true, // 单数表名
},
})
if err != nil {
log.Printf("[store] postgres 不可用,降级运行(不持久化): %v", err)
return &Postgres{}
}
if err := db.AutoMigrate(&User{}, &Task{}); err != nil {
log.Printf("[store] postgres AutoMigrate 失败,降级运行: %v", err)
return &Postgres{}
}
log.Println("[store] postgres connected, migrated sundynix_user / sundynix_task")
return &Postgres{db: db}
}
// Enabled 报告是否处于真实持久化模式。
func (p *Postgres) Enabled() bool { return p.db != nil }
// SaveTask 持久化一次任务提交(best-effort:降级模式下静默跳过)。
func (p *Postgres) SaveTask(ctx context.Context, id, graph string) error {
if p.db == nil {
return nil
}
return p.db.WithContext(ctx).Create(&Task{ID: id, Graph: graph, Status: "submitted"}).Error
}
// CountTasks 返回已提交任务数(降级模式返回 0)。
func (p *Postgres) CountTasks(ctx context.Context) (int64, error) {
if p.db == nil {
return 0, nil
}
var n int64
err := p.db.WithContext(ctx).Model(&Task{}).Count(&n).Error
return n, err
}
// Close 释放底层连接。
func (p *Postgres) Close() {
if p.db == nil {
return
}
if sqlDB, err := p.db.DB(); err == nil {
_ = sqlDB.Close()
}
}