You've already forked agentic-coding-workflow
fix(server): propagate shutdown error, http timeouts, ctx-aware migrate
This commit is contained in:
@@ -2,6 +2,7 @@
|
||||
package db
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
@@ -12,17 +13,33 @@ import (
|
||||
_ "github.com/golang-migrate/migrate/v4/source/file"
|
||||
)
|
||||
|
||||
// Migrate 跑指定路径下的迁移到最新版本。
|
||||
// Migrate 跑指定路径下的迁移到最新版本。ctx 取消可让本函数提前返回 ctx.Err(),
|
||||
// 但底层 golang-migrate 不接 ctx,已经 in-flight 的 Up() 会继续在后台 goroutine
|
||||
// 中执行直到自然完成(或外部 statement_timeout 触发)。
|
||||
// migrationsPath 形如 "file://migrations",dsn 为 postgres 连接串。
|
||||
// 当无新迁移可应用时(migrate.ErrNoChange)视为成功,返回 nil。
|
||||
func Migrate(dsn, migrationsPath string) error {
|
||||
func Migrate(ctx context.Context, dsn, migrationsPath string) error {
|
||||
m, err := migrate.New(migrationsPath, dsn)
|
||||
if err != nil {
|
||||
return fmt.Errorf("init migrate: %w", err)
|
||||
}
|
||||
defer func() { _, _ = m.Close() }()
|
||||
if err := m.Up(); err != nil && !errors.Is(err, migrate.ErrNoChange) {
|
||||
return fmt.Errorf("migrate up: %w", err)
|
||||
errCh := make(chan error, 1)
|
||||
go func() {
|
||||
if err := m.Up(); err != nil && !errors.Is(err, migrate.ErrNoChange) {
|
||||
errCh <- err
|
||||
return
|
||||
}
|
||||
errCh <- nil
|
||||
}()
|
||||
select {
|
||||
case err := <-errCh:
|
||||
_, _ = m.Close()
|
||||
if err != nil {
|
||||
return fmt.Errorf("migrate up: %w", err)
|
||||
}
|
||||
return nil
|
||||
case <-ctx.Done():
|
||||
// 注意:m.Close 不能在这里调,会与正在跑的 Up() 竞态。让 goroutine 自然结束。
|
||||
return ctx.Err()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user