mirror of
https://github.com/laoxong/nofx.git
synced 2026-06-04 01:48:22 +08:00
befc887a89
* fix(ci): add test encryption key for CI environment - Add DATA_ENCRYPTION_KEY environment variable to PR test workflow - Add test RSA public key for encryption tests in CI - Ensures unit tests pass in CI without production credentials Co-authored-by: tinkle-community <tinklefund@gmail.com> * fix(ci): install Go cover tool to eliminate covdata warnings - Add step to install golang.org/x/tools/cmd/cover in CI workflow - Use || true to prevent installation failure from breaking CI - Eliminates "no such tool covdata" warnings during test execution - Apply go fmt to multiple files for consistency Co-authored-by: tinkle-community <tinklefund@gmail.com> * fix(ci): install covdata tool for Go 1.23 coverage The CI was failing with "go: no such tool 'covdata'" error. This is because Go 1.23 requires the covdata tool to be installed for coverage reporting. Changes: - Install golang.org/x/tools/cmd/covdata in CI workflow - Update step name to reflect both coverage tools being installed Fixes the unit test failures in CI pipeline. Co-Authored-By: tinkle-community <tinklefund@gmail.com> * fix(ci): remove unnecessary covdata installation and use builtin go tool cover The previous attempt to install golang.org/x/tools/cmd/covdata was failing because the package structure changed in Go 1.23 and tools v0.38.0. The covdata tool is not needed for this project since we only use simple coverage reporting with go test -coverprofile. The go tool cover command is built into the Go toolchain and requires no additional installation. Changes: - Remove failed covdata and cover installation attempts - Add verification step for go tool cover availability - Simplify CI pipeline by eliminating unnecessary dependencies Co-authored-by: tinkle-community <tinklefund@gmail.com> * fix(ci): upgrade Go version to 1.25 to match go.mod declaration The CI was using Go 1.23 while go.mod declares go 1.25.0, causing "no such tool covdata" errors during coverage test compilation. Go 1.25's coverage infrastructure requires toolchain features not available in Go 1.23. This change aligns the CI Go version with the project's declared version requirement, ensuring the full Go 1.25 toolchain (including the covdata tool) is available for coverage testing. Co-authored-by: tinkle-community <tinklefund@gmail.com> --------- Co-authored-by: tinkle-community <tinklefund@gmail.com>
170 lines
4.1 KiB
Go
170 lines
4.1 KiB
Go
package bootstrap
|
||
|
||
import (
|
||
"fmt"
|
||
"log"
|
||
"nofx/logger"
|
||
"sort"
|
||
"sync"
|
||
"time"
|
||
)
|
||
|
||
// Priority 初始化优先级常量
|
||
const (
|
||
PriorityInfrastructure = 10 // 基础设施(日志、配置等)
|
||
PriorityDatabase = 20 // 数据库连接
|
||
PriorityCore = 50 // 核心模块(Proxy、Market等)
|
||
PriorityBusiness = 100 // 业务模块(Trader、API等)
|
||
PriorityBackground = 200 // 后台任务
|
||
)
|
||
|
||
// ErrorPolicy 错误处理策略
|
||
type ErrorPolicy int
|
||
|
||
const (
|
||
// FailFast 遇到错误立即停止(默认)
|
||
FailFast ErrorPolicy = iota
|
||
// ContinueOnError 继续执行,收集所有错误
|
||
ContinueOnError
|
||
// WarnOnError 继续执行,只打印警告
|
||
WarnOnError
|
||
)
|
||
|
||
var (
|
||
hooks []Hook
|
||
hooksMu sync.Mutex
|
||
)
|
||
|
||
// Register 注册初始化钩子
|
||
// name: 模块名称(如 "Proxy", "Database")
|
||
// priority: 优先级(建议使用常量:PriorityCore、PriorityBusiness等)
|
||
// fn: 初始化函数
|
||
func Register(name string, priority int, fn func(*Context) error) *HookBuilder {
|
||
hooksMu.Lock()
|
||
defer hooksMu.Unlock()
|
||
|
||
hook := Hook{
|
||
Name: name,
|
||
Priority: priority,
|
||
Func: fn,
|
||
Enabled: nil, // 默认启用
|
||
ErrorPolicy: FailFast,
|
||
}
|
||
|
||
hooks = append(hooks, hook)
|
||
|
||
return &HookBuilder{hook: &hooks[len(hooks)-1]}
|
||
}
|
||
|
||
// Run 执行所有已注册的钩子
|
||
func Run(ctx *Context) error {
|
||
return RunWithPolicy(ctx, FailFast)
|
||
}
|
||
|
||
// RunWithPolicy 使用指定的默认错误策略执行所有钩子
|
||
func RunWithPolicy(ctx *Context, defaultPolicy ErrorPolicy) error {
|
||
hooksMu.Lock()
|
||
hooksCopy := make([]Hook, len(hooks))
|
||
copy(hooksCopy, hooks)
|
||
hooksMu.Unlock()
|
||
|
||
if len(hooksCopy) == 0 {
|
||
log.Printf("⚠️ 没有注册任何初始化钩子")
|
||
return nil
|
||
}
|
||
|
||
// 按优先级排序
|
||
sort.Slice(hooksCopy, func(i, j int) bool {
|
||
return hooksCopy[i].Priority < hooksCopy[j].Priority
|
||
})
|
||
|
||
log.Printf("🔄 开始初始化 %d 个模块...", len(hooksCopy))
|
||
startTime := time.Now()
|
||
|
||
var errors []error
|
||
successCount := 0
|
||
skippedCount := 0
|
||
|
||
for i, hook := range hooksCopy {
|
||
// 检查是否启用
|
||
if hook.Enabled != nil && !hook.Enabled(ctx) {
|
||
log.Printf(" [%d/%d] 跳过: %s (条件未满足)",
|
||
i+1, len(hooksCopy), hook.Name)
|
||
skippedCount++
|
||
continue
|
||
}
|
||
|
||
log.Printf(" [%d/%d] 初始化: %s (优先级: %d)",
|
||
i+1, len(hooksCopy), hook.Name, hook.Priority)
|
||
|
||
hookStart := time.Now()
|
||
err := hook.Func(ctx)
|
||
elapsed := time.Since(hookStart)
|
||
|
||
if err != nil {
|
||
errMsg := fmt.Errorf("[%s] 初始化失败: %w", hook.Name, err)
|
||
|
||
// 根据错误策略处理
|
||
policy := hook.ErrorPolicy
|
||
if policy == FailFast && defaultPolicy != FailFast {
|
||
policy = defaultPolicy
|
||
}
|
||
|
||
switch policy {
|
||
case FailFast:
|
||
log.Printf(" ❌ 失败: %s (耗时: %v)", hook.Name, elapsed)
|
||
return errMsg
|
||
case ContinueOnError:
|
||
log.Printf(" ❌ 失败: %s (耗时: %v) - 继续执行", hook.Name, elapsed)
|
||
errors = append(errors, errMsg)
|
||
case WarnOnError:
|
||
log.Printf(" ⚠️ 警告: %s (耗时: %v) - %v", hook.Name, elapsed, err)
|
||
}
|
||
} else {
|
||
log.Printf(" ✓ 完成: %s (耗时: %v)", hook.Name, elapsed)
|
||
successCount++
|
||
}
|
||
}
|
||
|
||
totalElapsed := time.Since(startTime)
|
||
|
||
// 汇总结果
|
||
if len(errors) > 0 {
|
||
logger.Log.Warnf("⚠️ 初始化完成,但有 %d 个模块失败 (总耗时: %v)",
|
||
len(errors), totalElapsed)
|
||
log.Printf("📊 统计: 成功=%d, 失败=%d, 跳过=%d",
|
||
successCount, len(errors), skippedCount)
|
||
|
||
// 返回合并的错误
|
||
return fmt.Errorf("以下模块初始化失败: %v", errors)
|
||
}
|
||
|
||
log.Printf("✅ 所有模块初始化完成 (总耗时: %v)", totalElapsed)
|
||
log.Printf("📊 统计: 成功=%d, 跳过=%d", successCount, skippedCount)
|
||
return nil
|
||
}
|
||
|
||
// GetRegistered 获取已注册的钩子列表(用于调试)
|
||
func GetRegistered() []Hook {
|
||
hooksMu.Lock()
|
||
defer hooksMu.Unlock()
|
||
|
||
hooksCopy := make([]Hook, len(hooks))
|
||
copy(hooksCopy, hooks)
|
||
return hooksCopy
|
||
}
|
||
|
||
// Clear 清除所有钩子(用于测试)
|
||
func Clear() {
|
||
hooksMu.Lock()
|
||
defer hooksMu.Unlock()
|
||
hooks = nil
|
||
}
|
||
|
||
// Count 返回已注册的钩子数量
|
||
func Count() int {
|
||
hooksMu.Lock()
|
||
defer hooksMu.Unlock()
|
||
return len(hooks)
|
||
}
|