wire.go 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461
  1. //go:build wireinject
  2. // +build wireinject
  3. package main
  4. import (
  5. "context"
  6. "log"
  7. "net/http"
  8. "sync"
  9. "time"
  10. "github.com/Wei-Shaw/sub2api/ent"
  11. "github.com/Wei-Shaw/sub2api/internal/config"
  12. "github.com/Wei-Shaw/sub2api/internal/handler"
  13. "github.com/Wei-Shaw/sub2api/internal/payment"
  14. "github.com/Wei-Shaw/sub2api/internal/repository"
  15. "github.com/Wei-Shaw/sub2api/internal/securityaudit"
  16. "github.com/Wei-Shaw/sub2api/internal/server"
  17. "github.com/Wei-Shaw/sub2api/internal/server/middleware"
  18. "github.com/Wei-Shaw/sub2api/internal/service"
  19. "github.com/google/wire"
  20. "github.com/redis/go-redis/v9"
  21. )
  22. type Application struct {
  23. Server *http.Server
  24. PromptAudit *securityaudit.PromptService
  25. PluginManager *service.PluginManager
  26. Cleanup func()
  27. }
  28. func initializeApplication(buildInfo handler.BuildInfo) (*Application, error) {
  29. wire.Build(
  30. // Infrastructure layer ProviderSets
  31. config.ProviderSet,
  32. // Business layer ProviderSets
  33. repository.ProviderSet,
  34. service.ProviderSet,
  35. securityaudit.ProviderSet,
  36. payment.ProviderSet,
  37. middleware.ProviderSet,
  38. handler.ProviderSet,
  39. // Server layer ProviderSet
  40. server.ProviderSet,
  41. // Privacy client factory for OpenAI training opt-out
  42. providePrivacyClientFactory,
  43. // BuildInfo provider
  44. provideServiceBuildInfo,
  45. providePluginHostInfo,
  46. // Cleanup function provider
  47. provideCleanup,
  48. // Application struct
  49. wire.Struct(new(Application), "Server", "PromptAudit", "PluginManager", "Cleanup"),
  50. )
  51. return nil, nil
  52. }
  53. func providePrivacyClientFactory() service.PrivacyClientFactory {
  54. return repository.CreatePrivacyReqClient
  55. }
  56. func provideServiceBuildInfo(buildInfo handler.BuildInfo) service.BuildInfo {
  57. return service.BuildInfo{
  58. Version: buildInfo.Version,
  59. BuildType: buildInfo.BuildType,
  60. }
  61. }
  62. func providePluginHostInfo(buildInfo handler.BuildInfo) service.PluginHostInfo {
  63. return service.PluginHostInfo{
  64. Version: buildInfo.Version,
  65. BuildType: buildInfo.BuildType,
  66. }
  67. }
  68. func provideCleanup(
  69. entClient *ent.Client,
  70. rdb *redis.Client,
  71. opsMetricsCollector *service.OpsMetricsCollector,
  72. opsAggregation *service.OpsAggregationService,
  73. opsAlertEvaluator *service.OpsAlertEvaluatorService,
  74. opsCleanup *service.OpsCleanupService,
  75. opsScheduledReport *service.OpsScheduledReportService,
  76. opsSystemLogSink *service.OpsSystemLogSink,
  77. opsService *service.OpsService,
  78. opsIngressReject *service.OpsIngressRejectAggregator,
  79. apiKeyService *service.APIKeyService,
  80. authCacheInvalidationWorker *service.AuthCacheInvalidationWorker,
  81. schedulerSnapshot *service.SchedulerSnapshotService,
  82. tokenRefresh *service.TokenRefreshService,
  83. accountExpiry *service.AccountExpiryService,
  84. cnProviderBalanceCheck *service.CNProviderBalanceCheckService,
  85. codexVersionSync *service.OpenAICodexVersionSyncService,
  86. proxyExpiry *service.ProxyExpiryService,
  87. accountHealth *service.AccountHealthService,
  88. margin *service.MarginService,
  89. spendGuard *service.SpendGuardService,
  90. subscriptionExpiry *service.SubscriptionExpiryService,
  91. usageCleanup *service.UsageCleanupService,
  92. idempotencyCleanup *service.IdempotencyCleanupService,
  93. batchImageCleanup *service.BatchImageCleanupService,
  94. batchImageWorker *service.BatchImageWorkerRuntime,
  95. pricing *service.PricingService,
  96. emailQueue *service.EmailQueueService,
  97. billingCache *service.BillingCacheService,
  98. usageRecordWorkerPool *service.UsageRecordWorkerPool,
  99. subscriptionService *service.SubscriptionService,
  100. oauth *service.OAuthService,
  101. openaiOAuth *service.OpenAIOAuthService,
  102. geminiOAuth *service.GeminiOAuthService,
  103. antigravityOAuth *service.AntigravityOAuthService,
  104. grokOAuth *service.GrokOAuthService,
  105. openAIGateway *service.OpenAIGatewayService,
  106. scheduledTestRunner *service.ScheduledTestRunnerService,
  107. intelligentTests *service.IntelligentTestService,
  108. backupSvc *service.BackupService,
  109. paymentOrderExpiry *service.PaymentOrderExpiryService,
  110. channelMonitorRunner *service.ChannelMonitorRunner,
  111. channelMonitorV2Aggregator *service.ChannelMonitorV2Aggregator,
  112. quotaFlusher *service.UserPlatformQuotaUsageFlusher,
  113. upstreamBillingProbe *service.UpstreamBillingProbeService,
  114. ollamaCloudUsage *service.OllamaCloudUsageService,
  115. auditLog *service.AuditLogService,
  116. openAIAutoReset *service.OpenAIQuotaAutoResetService,
  117. promptAudit *securityaudit.PromptService,
  118. pluginManager *service.PluginManager,
  119. ) func() {
  120. return func() {
  121. ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
  122. defer cancel()
  123. type cleanupStep struct {
  124. name string
  125. fn func() error
  126. }
  127. // 应用层清理步骤可并行执行,基础设施资源(Redis/Ent)最后按顺序关闭。
  128. parallelSteps := []cleanupStep{
  129. {"IntelligentTests", func() error {
  130. if intelligentTests != nil {
  131. intelligentTests.Stop()
  132. }
  133. return nil
  134. }},
  135. {"PluginManager", func() error {
  136. if pluginManager != nil {
  137. pluginManager.Stop()
  138. }
  139. return nil
  140. }},
  141. {"OpenAIQuotaAutoResetService", func() error {
  142. if openAIAutoReset != nil {
  143. openAIAutoReset.Stop()
  144. }
  145. return nil
  146. }},
  147. {"OpsIngressRejectAggregator", func() error {
  148. if opsIngressReject != nil {
  149. opsIngressReject.Stop()
  150. }
  151. return nil
  152. }},
  153. {"AuthCacheInvalidationWorker", func() error {
  154. if authCacheInvalidationWorker != nil {
  155. authCacheInvalidationWorker.Stop()
  156. }
  157. return nil
  158. }},
  159. {"AuthCacheInvalidationSubscriber", func() error {
  160. if apiKeyService != nil {
  161. apiKeyService.StopAuthCacheInvalidationSubscriber()
  162. }
  163. return nil
  164. }},
  165. {"OpsRuntimeSettingsRefresh", func() error {
  166. if opsService != nil {
  167. opsService.StopRuntimeSettingsRefresh()
  168. }
  169. return nil
  170. }},
  171. {"PromptAuditService", func() error {
  172. if promptAudit != nil {
  173. return promptAudit.Shutdown(ctx)
  174. }
  175. return nil
  176. }},
  177. {"OpsScheduledReportService", func() error {
  178. if opsScheduledReport != nil {
  179. opsScheduledReport.Stop()
  180. }
  181. return nil
  182. }},
  183. {"OpsCleanupService", func() error {
  184. if opsCleanup != nil {
  185. opsCleanup.Stop()
  186. }
  187. return nil
  188. }},
  189. {"OpsSystemLogSink", func() error {
  190. if opsSystemLogSink != nil {
  191. opsSystemLogSink.Stop()
  192. }
  193. return nil
  194. }},
  195. {"AuditLogService", func() error {
  196. if auditLog != nil {
  197. auditLog.Stop()
  198. }
  199. return nil
  200. }},
  201. {"OpsAlertEvaluatorService", func() error {
  202. if opsAlertEvaluator != nil {
  203. opsAlertEvaluator.Stop()
  204. }
  205. return nil
  206. }},
  207. {"OpsAggregationService", func() error {
  208. if opsAggregation != nil {
  209. opsAggregation.Stop()
  210. }
  211. return nil
  212. }},
  213. {"OpsMetricsCollector", func() error {
  214. if opsMetricsCollector != nil {
  215. opsMetricsCollector.Stop()
  216. }
  217. return nil
  218. }},
  219. {"SchedulerSnapshotService", func() error {
  220. if schedulerSnapshot != nil {
  221. schedulerSnapshot.Stop()
  222. }
  223. return nil
  224. }},
  225. {"UsageCleanupService", func() error {
  226. if usageCleanup != nil {
  227. usageCleanup.Stop()
  228. }
  229. return nil
  230. }},
  231. {"IdempotencyCleanupService", func() error {
  232. if idempotencyCleanup != nil {
  233. idempotencyCleanup.Stop()
  234. }
  235. return nil
  236. }},
  237. {"BatchImageCleanupService", func() error {
  238. if batchImageCleanup != nil {
  239. batchImageCleanup.Stop()
  240. }
  241. return nil
  242. }},
  243. {"BatchImageWorkerRuntime", func() error {
  244. if batchImageWorker != nil {
  245. batchImageWorker.Stop()
  246. }
  247. return nil
  248. }},
  249. {"TokenRefreshService", func() error {
  250. tokenRefresh.Stop()
  251. return nil
  252. }},
  253. {"AccountExpiryService", func() error {
  254. accountExpiry.Stop()
  255. return nil
  256. }},
  257. {"CNProviderBalanceCheckService", func() error {
  258. if cnProviderBalanceCheck != nil {
  259. cnProviderBalanceCheck.Stop()
  260. }
  261. return nil
  262. }},
  263. {"OpenAICodexVersionSyncService", func() error {
  264. codexVersionSync.Stop()
  265. return nil
  266. }},
  267. {"ProxyExpiryService", func() error {
  268. proxyExpiry.Stop()
  269. return nil
  270. }},
  271. {"AccountHealthService", func() error {
  272. accountHealth.Stop()
  273. return nil
  274. }},
  275. {"MarginService", func() error {
  276. margin.Stop()
  277. return nil
  278. }},
  279. {"SpendGuardService", func() error {
  280. spendGuard.Stop()
  281. return nil
  282. }},
  283. {"SubscriptionExpiryService", func() error {
  284. subscriptionExpiry.Stop()
  285. return nil
  286. }},
  287. {"SubscriptionService", func() error {
  288. if subscriptionService != nil {
  289. subscriptionService.Stop()
  290. }
  291. return nil
  292. }},
  293. {"PricingService", func() error {
  294. pricing.Stop()
  295. return nil
  296. }},
  297. {"EmailQueueService", func() error {
  298. emailQueue.Stop()
  299. return nil
  300. }},
  301. {"BillingCacheService", func() error {
  302. billingCache.Stop()
  303. return nil
  304. }},
  305. {"UsageRecordWorkerPool", func() error {
  306. if usageRecordWorkerPool != nil {
  307. usageRecordWorkerPool.Stop()
  308. }
  309. return nil
  310. }},
  311. {"OAuthService", func() error {
  312. oauth.Stop()
  313. return nil
  314. }},
  315. {"OpenAIOAuthService", func() error {
  316. openaiOAuth.Stop()
  317. return nil
  318. }},
  319. {"GeminiOAuthService", func() error {
  320. geminiOAuth.Stop()
  321. return nil
  322. }},
  323. {"AntigravityOAuthService", func() error {
  324. antigravityOAuth.Stop()
  325. return nil
  326. }},
  327. {"GrokOAuthService", func() error {
  328. if grokOAuth != nil {
  329. grokOAuth.Stop()
  330. }
  331. return nil
  332. }},
  333. {"OpenAIWSPool", func() error {
  334. if openAIGateway != nil {
  335. openAIGateway.CloseOpenAIWSPool()
  336. }
  337. return nil
  338. }},
  339. {"ScheduledTestRunnerService", func() error {
  340. if scheduledTestRunner != nil {
  341. scheduledTestRunner.Stop()
  342. }
  343. return nil
  344. }},
  345. {"BackupService", func() error {
  346. if backupSvc != nil {
  347. backupSvc.Stop()
  348. }
  349. return nil
  350. }},
  351. {"PaymentOrderExpiryService", func() error {
  352. if paymentOrderExpiry != nil {
  353. paymentOrderExpiry.Stop()
  354. }
  355. return nil
  356. }},
  357. {"ChannelMonitorV2Aggregator", func() error {
  358. if channelMonitorV2Aggregator != nil {
  359. channelMonitorV2Aggregator.Stop()
  360. }
  361. return nil
  362. }},
  363. {"ChannelMonitorRunner", func() error {
  364. if channelMonitorRunner != nil {
  365. channelMonitorRunner.Stop()
  366. }
  367. return nil
  368. }},
  369. {"UserPlatformQuotaUsageFlusher", func() error {
  370. if quotaFlusher != nil {
  371. quotaFlusher.Stop()
  372. }
  373. return nil
  374. }},
  375. {"UpstreamBillingProbeService", func() error {
  376. if upstreamBillingProbe != nil {
  377. upstreamBillingProbe.Stop()
  378. }
  379. return nil
  380. }},
  381. {"OllamaCloudUsageService", func() error {
  382. if ollamaCloudUsage != nil {
  383. ollamaCloudUsage.Stop()
  384. }
  385. return nil
  386. }},
  387. }
  388. infraSteps := []cleanupStep{
  389. {"Redis", func() error {
  390. if rdb == nil {
  391. return nil
  392. }
  393. return rdb.Close()
  394. }},
  395. {"Ent", func() error {
  396. if entClient == nil {
  397. return nil
  398. }
  399. return entClient.Close()
  400. }},
  401. }
  402. runParallel := func(steps []cleanupStep) {
  403. var wg sync.WaitGroup
  404. for i := range steps {
  405. step := steps[i]
  406. wg.Add(1)
  407. go func() {
  408. defer wg.Done()
  409. if err := step.fn(); err != nil {
  410. log.Printf("[Cleanup] %s failed: %v", step.name, err)
  411. return
  412. }
  413. log.Printf("[Cleanup] %s succeeded", step.name)
  414. }()
  415. }
  416. wg.Wait()
  417. }
  418. runSequential := func(steps []cleanupStep) {
  419. for i := range steps {
  420. step := steps[i]
  421. if err := step.fn(); err != nil {
  422. log.Printf("[Cleanup] %s failed: %v", step.name, err)
  423. continue
  424. }
  425. log.Printf("[Cleanup] %s succeeded", step.name)
  426. }
  427. }
  428. runParallel(parallelSteps)
  429. runSequential(infraSteps)
  430. // Check if context timed out
  431. select {
  432. case <-ctx.Done():
  433. log.Printf("[Cleanup] Warning: cleanup timed out after 10 seconds")
  434. default:
  435. log.Printf("[Cleanup] All cleanup steps completed")
  436. }
  437. }
  438. }