mirror of
https://github.com/Rain-kl/OpenFlare.git
synced 2026-10-01 22:46:38 +08:00
feat(startup): print service banner after listener ready
This commit is contained in:
+3
-1
@@ -31,7 +31,9 @@ var allCmd = &cobra.Command{
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
log.Println("[All] 启动 API 服务")
|
||||
router.Serve()
|
||||
router.Serve(func() {
|
||||
printStartupBanner(startupState{mode: "API + Worker + Scheduler", relationalDB: latestMigrationState.relationalDB, clickHouseDB: latestMigrationState.clickHouseDB, listensForHTTP: true})
|
||||
})
|
||||
}()
|
||||
|
||||
// 启动 Asynq Worker 任务处理服务
|
||||
|
||||
+3
-1
@@ -16,6 +16,8 @@ var apiCmd = &cobra.Command{
|
||||
Run: func(_ *cobra.Command, _ []string) {
|
||||
bootstrap.RegisterAPI()
|
||||
runBootstrap(bootstrap.Options{API: true})
|
||||
router.Serve()
|
||||
router.Serve(func() {
|
||||
printStartupBanner(startupState{mode: "API", relationalDB: latestMigrationState.relationalDB, clickHouseDB: latestMigrationState.clickHouseDB, listensForHTTP: true})
|
||||
})
|
||||
},
|
||||
}
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
// Copyright 2026 Arctel.net
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"runtime"
|
||||
"strings"
|
||||
|
||||
"github.com/Rain-kl/Wavelet/internal/buildinfo"
|
||||
"github.com/Rain-kl/Wavelet/internal/config"
|
||||
"github.com/Rain-kl/Wavelet/internal/db/migrator"
|
||||
)
|
||||
|
||||
type startupState struct {
|
||||
mode string
|
||||
relationalDB migrator.Report
|
||||
clickHouseDB migrator.Report
|
||||
listensForHTTP bool
|
||||
}
|
||||
|
||||
func printStartupBanner(state startupState) {
|
||||
log.Print(formatStartupBanner(state))
|
||||
}
|
||||
|
||||
func formatStartupBanner(state startupState) string {
|
||||
lines := []string{
|
||||
"",
|
||||
" ____ ________ ",
|
||||
" / __ \\____ ___ ____ / ____/ /___ _________ ",
|
||||
" / / / / __ \\/ _ \\/ __ \\/ /_ / / __ `/ ___/ _ \\",
|
||||
"/ /_/ / /_/ / __/ / / / __/ / / /_/ / / / __/",
|
||||
"\\____/ .___/\\___/_/ /_/_/ /_/\\__,_/_/ \\___/ ",
|
||||
" /_/ ",
|
||||
fmt.Sprintf(" OpenFlare %s", buildinfo.Version),
|
||||
"",
|
||||
fmt.Sprintf(" Environment: %s", config.Config.App.Env),
|
||||
fmt.Sprintf(" Runtime: %s/%s (%s)", runtime.GOOS, runtime.GOARCH, runtime.Version()),
|
||||
fmt.Sprintf(" Build time: %s", buildTime()),
|
||||
fmt.Sprintf(" Database: %s", formatMigration(state.relationalDB)),
|
||||
fmt.Sprintf(" Analytics: %s", formatMigration(state.clickHouseDB)),
|
||||
}
|
||||
if state.listensForHTTP {
|
||||
lines = append(lines, fmt.Sprintf(" Listening: http://%s", config.Config.App.Addr))
|
||||
}
|
||||
lines = append(lines, fmt.Sprintf(" Mode: %s", state.mode), "")
|
||||
return strings.Join(lines, "\n")
|
||||
}
|
||||
|
||||
func buildTime() string {
|
||||
if buildinfo.BuildTime == "" {
|
||||
return "development build"
|
||||
}
|
||||
return buildinfo.BuildTime
|
||||
}
|
||||
|
||||
func formatMigration(report migrator.Report) string {
|
||||
if !report.Enabled {
|
||||
return "disabled"
|
||||
}
|
||||
state := "up to date"
|
||||
if report.Applied {
|
||||
state = "upgraded"
|
||||
}
|
||||
return fmt.Sprintf("%s (version %d, %s)", report.Backend, report.Version, state)
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
// Copyright 2026 Arctel.net
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/Rain-kl/Wavelet/internal/buildinfo"
|
||||
"github.com/Rain-kl/Wavelet/internal/config"
|
||||
"github.com/Rain-kl/Wavelet/internal/db/migrator"
|
||||
)
|
||||
|
||||
func TestFormatStartupBanner(t *testing.T) {
|
||||
previousVersion := buildinfo.Version
|
||||
previousBuildTime := buildinfo.BuildTime
|
||||
previousEnv := config.Config.App.Env
|
||||
previousAddr := config.Config.App.Addr
|
||||
t.Cleanup(func() {
|
||||
buildinfo.Version = previousVersion
|
||||
buildinfo.BuildTime = previousBuildTime
|
||||
config.Config.App.Env = previousEnv
|
||||
config.Config.App.Addr = previousAddr
|
||||
})
|
||||
|
||||
buildinfo.Version = "v3.2.1"
|
||||
buildinfo.BuildTime = "2026-07-13T08:00:00Z"
|
||||
config.Config.App.Env = "production"
|
||||
config.Config.App.Addr = ":3000"
|
||||
|
||||
banner := formatStartupBanner(startupState{
|
||||
mode: "API",
|
||||
relationalDB: migrator.Report{
|
||||
Backend: "PostgreSQL",
|
||||
Enabled: true,
|
||||
Version: 202607150003,
|
||||
Applied: true,
|
||||
},
|
||||
clickHouseDB: migrator.Report{Backend: "ClickHouse"},
|
||||
listensForHTTP: true,
|
||||
})
|
||||
|
||||
for _, want := range []string{
|
||||
"OpenFlare v3.2.1",
|
||||
"Environment: production",
|
||||
"Build time: 2026-07-13T08:00:00Z",
|
||||
"Database: PostgreSQL (version 202607150003, upgraded)",
|
||||
"Analytics: disabled",
|
||||
"Listening: http://:3000",
|
||||
"Mode: API",
|
||||
} {
|
||||
if !strings.Contains(banner, want) {
|
||||
t.Errorf("banner missing %q:\n%s", want, banner)
|
||||
}
|
||||
}
|
||||
}
|
||||
+12
-4
@@ -39,8 +39,7 @@ var rootCmd = &cobra.Command{
|
||||
})
|
||||
},
|
||||
PreRun: func(_ *cobra.Command, _ []string) {
|
||||
migrator.Migrate()
|
||||
migrator.MigrateClickHouse()
|
||||
runMigrations()
|
||||
},
|
||||
PersistentPostRun: func(_ *cobra.Command, _ []string) {
|
||||
shutdownTraceProvider()
|
||||
@@ -51,6 +50,16 @@ var rootCmd = &cobra.Command{
|
||||
},
|
||||
}
|
||||
|
||||
var latestMigrationState struct {
|
||||
relationalDB migrator.Report
|
||||
clickHouseDB migrator.Report
|
||||
}
|
||||
|
||||
func runMigrations() {
|
||||
latestMigrationState.relationalDB = migrator.Migrate()
|
||||
latestMigrationState.clickHouseDB = migrator.MigrateClickHouse()
|
||||
}
|
||||
|
||||
func shutdownTraceProvider() {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), traceShutdownTimeout)
|
||||
defer cancel()
|
||||
@@ -63,8 +72,7 @@ func init() {
|
||||
|
||||
// 1. 为需要迁移的子命令动态绑定原先 rootCmd.PreRun 拥有的数据库迁移行为
|
||||
migratePreRun := func(_ *cobra.Command, _ []string) {
|
||||
migrator.Migrate()
|
||||
migrator.MigrateClickHouse()
|
||||
runMigrations()
|
||||
}
|
||||
allCmd.PreRun = migratePreRun
|
||||
apiCmd.PreRun = migratePreRun
|
||||
|
||||
@@ -18,6 +18,7 @@ var schedulerCmd = &cobra.Command{
|
||||
Short: "wavelet Scheduler",
|
||||
Run: func(_ *cobra.Command, _ []string) {
|
||||
runBootstrap(bootstrap.Options{})
|
||||
printStartupBanner(startupState{mode: "Scheduler", relationalDB: latestMigrationState.relationalDB, clickHouseDB: latestMigrationState.clickHouseDB})
|
||||
log.Println("[Scheduler] 启动定时任务调度服务")
|
||||
if err := scheduler.StartScheduler(); err != nil {
|
||||
log.Fatalf("[调度器] 启动失败: %v", err)
|
||||
|
||||
@@ -18,6 +18,7 @@ var workerCmd = &cobra.Command{
|
||||
Short: "wavelet Worker",
|
||||
Run: func(_ *cobra.Command, _ []string) {
|
||||
runBootstrap(bootstrap.Options{})
|
||||
printStartupBanner(startupState{mode: "Worker", relationalDB: latestMigrationState.relationalDB, clickHouseDB: latestMigrationState.clickHouseDB})
|
||||
log.Println("[Worker] 启动任务处理服务")
|
||||
if err := worker.StartWorker(); err != nil {
|
||||
log.Fatalf("[工作器] 启动失败: %v", err)
|
||||
|
||||
Reference in New Issue
Block a user