fix startup bootstrap recovery and local verification
This commit is contained in:
@@ -150,6 +150,9 @@ func runMainServer() {
|
||||
log.Fatalf("Failed to initialize application: %v", err)
|
||||
}
|
||||
defer app.Cleanup()
|
||||
if err := app.Bootstrap(); err != nil {
|
||||
log.Fatalf("Failed to bootstrap application state: %v", err)
|
||||
}
|
||||
|
||||
// 启动服务器
|
||||
go func() {
|
||||
|
||||
@@ -18,14 +18,16 @@ import (
|
||||
"github.com/Wei-Shaw/sub2api/internal/server"
|
||||
"github.com/Wei-Shaw/sub2api/internal/server/middleware"
|
||||
"github.com/Wei-Shaw/sub2api/internal/service"
|
||||
"github.com/Wei-Shaw/sub2api/internal/setup"
|
||||
|
||||
"github.com/google/wire"
|
||||
"github.com/redis/go-redis/v9"
|
||||
)
|
||||
|
||||
type Application struct {
|
||||
Server *http.Server
|
||||
Cleanup func()
|
||||
Server *http.Server
|
||||
Cleanup func()
|
||||
Bootstrap func() error
|
||||
}
|
||||
|
||||
func initializeApplication(buildInfo handler.BuildInfo) (*Application, error) {
|
||||
@@ -53,9 +55,10 @@ func initializeApplication(buildInfo handler.BuildInfo) (*Application, error) {
|
||||
|
||||
// Cleanup function provider
|
||||
provideCleanup,
|
||||
provideBootstrap,
|
||||
|
||||
// Application struct
|
||||
wire.Struct(new(Application), "Server", "Cleanup"),
|
||||
wire.Struct(new(Application), "Server", "Cleanup", "Bootstrap"),
|
||||
)
|
||||
return nil, nil
|
||||
}
|
||||
@@ -71,6 +74,28 @@ func provideServiceBuildInfo(buildInfo handler.BuildInfo) service.BuildInfo {
|
||||
}
|
||||
}
|
||||
|
||||
func provideBootstrap(settingService *service.SettingService, userRepo service.UserRepository, cfg *config.Config) func() error {
|
||||
return newBootstrapFunc(settingService.InitializeDefaultSettings, setup.RecoverAutoSetupAdmin, userRepo, cfg)
|
||||
}
|
||||
|
||||
func newBootstrapFunc(
|
||||
initDefaults func(context.Context) error,
|
||||
recoverAdmin func(context.Context, service.UserRepository, *config.Config) error,
|
||||
userRepo service.UserRepository,
|
||||
cfg *config.Config,
|
||||
) func() error {
|
||||
return func() error {
|
||||
ctx := context.Background()
|
||||
if err := initDefaults(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := recoverAdmin(ctx, userRepo, cfg); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func provideCleanup(
|
||||
entClient *ent.Client,
|
||||
rdb *redis.Client,
|
||||
|
||||
@@ -17,6 +17,7 @@ import (
|
||||
"github.com/Wei-Shaw/sub2api/internal/server"
|
||||
"github.com/Wei-Shaw/sub2api/internal/server/middleware"
|
||||
"github.com/Wei-Shaw/sub2api/internal/service"
|
||||
"github.com/Wei-Shaw/sub2api/internal/setup"
|
||||
"github.com/redis/go-redis/v9"
|
||||
"log"
|
||||
"net/http"
|
||||
@@ -260,9 +261,11 @@ func initializeApplication(buildInfo handler.BuildInfo) (*Application, error) {
|
||||
scheduledTestRunnerService := service.ProvideScheduledTestRunnerService(scheduledTestPlanRepository, scheduledTestService, accountTestService, rateLimitService, configConfig)
|
||||
paymentOrderExpiryService := service.ProvidePaymentOrderExpiryService(paymentService)
|
||||
v := provideCleanup(client, redisClient, opsMetricsCollector, opsAggregationService, opsAlertEvaluatorService, opsCleanupService, opsScheduledReportService, opsSystemLogSink, soraMediaCleanupService, schedulerSnapshotService, tokenRefreshService, accountExpiryService, subscriptionExpiryService, usageCleanupService, idempotencyCleanupService, pricingService, emailQueueService, billingCacheService, usageRecordWorkerPool, subscriptionService, oAuthService, openAIOAuthService, geminiOAuthService, antigravityOAuthService, openAIGatewayService, scheduledTestRunnerService, backupService, paymentOrderExpiryService)
|
||||
bootstrap := provideBootstrap(settingService, userRepository, configConfig)
|
||||
application := &Application{
|
||||
Server: httpServer,
|
||||
Cleanup: v,
|
||||
Server: httpServer,
|
||||
Cleanup: v,
|
||||
Bootstrap: bootstrap,
|
||||
}
|
||||
return application, nil
|
||||
}
|
||||
@@ -270,8 +273,9 @@ func initializeApplication(buildInfo handler.BuildInfo) (*Application, error) {
|
||||
// wire.go:
|
||||
|
||||
type Application struct {
|
||||
Server *http.Server
|
||||
Cleanup func()
|
||||
Server *http.Server
|
||||
Cleanup func()
|
||||
Bootstrap func() error
|
||||
}
|
||||
|
||||
func providePrivacyClientFactory() service.PrivacyClientFactory {
|
||||
@@ -285,6 +289,23 @@ func provideServiceBuildInfo(buildInfo handler.BuildInfo) service.BuildInfo {
|
||||
}
|
||||
}
|
||||
|
||||
func provideBootstrap(settingService *service.SettingService, userRepo service.UserRepository, cfg *config.Config) func() error {
|
||||
return newBootstrapFunc(settingService.InitializeDefaultSettings, setup.RecoverAutoSetupAdmin, userRepo, cfg)
|
||||
}
|
||||
|
||||
func newBootstrapFunc(initDefaults func(context.Context) error, recoverAdmin func(context.Context, service.UserRepository, *config.Config) error, userRepo service.UserRepository, cfg *config.Config) func() error {
|
||||
return func() error {
|
||||
ctx := context.Background()
|
||||
if err := initDefaults(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := recoverAdmin(ctx, userRepo, cfg); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func provideCleanup(
|
||||
entClient *ent.Client,
|
||||
rdb *redis.Client,
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
@@ -83,3 +85,47 @@ func TestProvideCleanup_WithMinimalDependencies_NoPanic(t *testing.T) {
|
||||
cleanup()
|
||||
})
|
||||
}
|
||||
|
||||
func TestNewBootstrapFunc_RunsDefaultsBeforeRecovery(t *testing.T) {
|
||||
cfg := &config.Config{}
|
||||
order := make([]string, 0, 2)
|
||||
|
||||
bootstrap := newBootstrapFunc(
|
||||
func(context.Context) error {
|
||||
order = append(order, "defaults")
|
||||
return nil
|
||||
},
|
||||
func(_ context.Context, gotRepo service.UserRepository, got *config.Config) error {
|
||||
require.Nil(t, gotRepo)
|
||||
require.Same(t, cfg, got)
|
||||
order = append(order, "recover")
|
||||
return nil
|
||||
},
|
||||
nil,
|
||||
cfg,
|
||||
)
|
||||
|
||||
require.NoError(t, bootstrap())
|
||||
require.Equal(t, []string{"defaults", "recover"}, order)
|
||||
}
|
||||
|
||||
func TestNewBootstrapFunc_StopsWhenDefaultsFail(t *testing.T) {
|
||||
cfg := &config.Config{}
|
||||
wantErr := errors.New("defaults failed")
|
||||
recoverCalled := false
|
||||
|
||||
bootstrap := newBootstrapFunc(
|
||||
func(context.Context) error {
|
||||
return wantErr
|
||||
},
|
||||
func(context.Context, service.UserRepository, *config.Config) error {
|
||||
recoverCalled = true
|
||||
return nil
|
||||
},
|
||||
nil,
|
||||
cfg,
|
||||
)
|
||||
|
||||
require.ErrorIs(t, bootstrap(), wantErr)
|
||||
require.False(t, recoverCalled)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user