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>
This commit is contained in:
@@ -1,14 +1,70 @@
|
||||
// Package store 封装 MainDB(PgSQL) 与 CacheDB(Redis) 的访问。
|
||||
package store
|
||||
|
||||
import "log"
|
||||
import (
|
||||
"context"
|
||||
"log"
|
||||
|
||||
// Postgres 持有 MainDB 连接池(Users / Billing / DSL)。
|
||||
type Postgres struct{ /* *pgxpool.Pool */ }
|
||||
"gorm.io/driver/postgres"
|
||||
"gorm.io/gorm"
|
||||
"gorm.io/gorm/schema"
|
||||
)
|
||||
|
||||
// MustOpenPostgres 建立 Postgres 连接,失败即退出。
|
||||
func MustOpenPostgres() *Postgres {
|
||||
// TODO: pgxpool.New(ctx, dsn)
|
||||
log.Println("[store] postgres connected (stub)")
|
||||
return &Postgres{}
|
||||
// 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()
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user