Açıklama Yok
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

bootstrap.go 10KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387
  1. package bootstraps
  2. import (
  3. "context"
  4. "fmt"
  5. "log"
  6. "net/http"
  7. "os"
  8. "os/signal"
  9. "syscall"
  10. "time"
  11. "git.x2erp.com/qdy/go-base/config"
  12. "git.x2erp.com/qdy/go-base/config/subconfigs"
  13. "git.x2erp.com/qdy/go-base/logger"
  14. )
  15. // 定义接口
  16. type ShutdownHandler interface {
  17. OnShutdown()
  18. }
  19. // WebService Web服务实例
  20. type WebService struct {
  21. serviceName string
  22. serviceConfig *subconfigs.ServiceConfig
  23. HttpServer *http.Server
  24. Router *http.ServeMux
  25. quit chan os.Signal
  26. shutdownHandler ShutdownHandler
  27. }
  28. // Bootstrapper 服务启动器
  29. type Bootstrapper struct {
  30. appName string
  31. appVersion string
  32. Cfg config.IConfig
  33. services map[string]*WebService // 存储多个服务实例
  34. quit chan os.Signal
  35. }
  36. // NewBootstrapper 创建启动器
  37. func NewBootstrapper(name, version string) *Bootstrapper {
  38. b := &Bootstrapper{
  39. appName: name,
  40. appVersion: version,
  41. quit: make(chan os.Signal, 1),
  42. services: make(map[string]*WebService),
  43. }
  44. b.init()
  45. return b
  46. }
  47. // Init 初始化配置和日志
  48. func (b *Bootstrapper) init() *Bootstrapper {
  49. // 1. 初始化启动日志
  50. if err := logger.InitBootLog(b.appName); err != nil {
  51. log.Fatal("无法初始化启动日志: ", err)
  52. }
  53. // 2. 加载配置
  54. log.Println("正在加载配置...")
  55. cfg, err := config.GetConfig()
  56. if err != nil {
  57. log.Fatalf("加载配置失败: %v", err)
  58. }
  59. cfg.SetAppName(b.appName)
  60. cfg.SetAppVersion(b.appVersion)
  61. b.Cfg = cfg
  62. // 3. 初始化运行时日志
  63. logger.InitRuntimeLogger(b.appName, b.appVersion, b.Cfg.GetLog())
  64. log.Println("配置和日志初始化完成")
  65. return b
  66. }
  67. // CreateService 创建Web服务实例
  68. func (b *Bootstrapper) CreateService(serviceName string) *WebService {
  69. serviceCfg := b.Cfg.GetServiceConfig(serviceName)
  70. // 检查是否已存在同名服务
  71. if _, exists := b.services[serviceName]; exists {
  72. logger.Debug("服务 %s 已存在,将返回现有实例", serviceName)
  73. return b.services[serviceName]
  74. }
  75. // 创建新的服务实例
  76. ws := &WebService{
  77. serviceName: serviceName,
  78. serviceConfig: serviceCfg,
  79. Router: http.NewServeMux(),
  80. quit: make(chan os.Signal, 1),
  81. }
  82. // 创建HTTP服务器
  83. ws.HttpServer = &http.Server{
  84. Addr: fmt.Sprintf(":%d", serviceCfg.Port),
  85. Handler: ws.Router,
  86. ReadTimeout: 15 * time.Second,
  87. WriteTimeout: 15 * time.Second,
  88. IdleTimeout: 60 * time.Second,
  89. }
  90. // 存储服务实例
  91. b.services[serviceName] = ws
  92. logger.Debug("已创建服务实例: %s (端口: %d)", serviceCfg.ServiceName, serviceCfg.Port)
  93. return ws
  94. }
  95. // GetAllServices 获取所有服务实例
  96. func (b *Bootstrapper) GetAllServices() map[string]*WebService {
  97. return b.services
  98. }
  99. // StartService 启动指定服务
  100. func (b *Bootstrapper) StartService(serviceName string) *Bootstrapper {
  101. service := b.CreateService(serviceName)
  102. serviceCfg := service.serviceConfig
  103. log.Printf("正在启动服务: %s ", serviceCfg.ServiceName)
  104. log.Printf("模式: 独立运行 (net/http)")
  105. log.Printf("服务端口: :%d", serviceCfg.Port)
  106. return b
  107. }
  108. // Run 运行所有服务
  109. func (b *Bootstrapper) Run(shutdownHandler ShutdownHandler) {
  110. if len(b.services) == 0 {
  111. log.Fatal("没有要运行的服务,请先创建服务实例")
  112. }
  113. log.Printf("开始运行 %d 个服务...", len(b.services))
  114. // 设置全局信号监听
  115. signal.Notify(b.quit, syscall.SIGINT, syscall.SIGTERM)
  116. // 启动所有服务
  117. for serviceName, service := range b.services {
  118. go func(name string, ws *WebService) {
  119. log.Printf("启动服务 %s 在 %s", name, ws.HttpServer.Addr)
  120. if err := ws.HttpServer.ListenAndServe(); err != nil && err != http.ErrServerClosed {
  121. log.Fatalf("服务 %s 运行失败: %v", name, err)
  122. }
  123. }(serviceName, service)
  124. }
  125. // 等待中断信号
  126. b.waitForShutdown(shutdownHandler)
  127. }
  128. // RunSingle 运行单个服务
  129. func (b *Bootstrapper) RunSingle(serviceName string, shutdownHandler ShutdownHandler) {
  130. service := b.CreateService(serviceName)
  131. log.Printf("服务 %s 开始运行...", service.serviceConfig.ServiceName)
  132. // 设置服务级别的信号监听
  133. signal.Notify(service.quit, syscall.SIGINT, syscall.SIGTERM)
  134. // 启动服务
  135. go func() {
  136. log.Printf("服务器启动在 %s", service.HttpServer.Addr)
  137. if err := service.HttpServer.ListenAndServe(); err != nil && err != http.ErrServerClosed {
  138. log.Fatalf("服务运行失败: %v", err)
  139. }
  140. }()
  141. // 等待中断信号
  142. b.waitForServiceShutdown(service, shutdownHandler)
  143. }
  144. // RunTLS 运行HTTPS服务
  145. func (b *Bootstrapper) RunTLS(serviceName, certFile, keyFile string, shutdownHandler ShutdownHandler) {
  146. service := b.CreateService(serviceName)
  147. log.Printf("服务 %s 开始运行(HTTPS)...", service.serviceConfig.ServiceName)
  148. // 设置服务级别的信号监听
  149. signal.Notify(service.quit, syscall.SIGINT, syscall.SIGTERM)
  150. // 启动HTTPS服务器
  151. go func() {
  152. log.Printf("HTTPS服务器启动在 %s", service.HttpServer.Addr)
  153. if err := service.HttpServer.ListenAndServeTLS(certFile, keyFile); err != nil && err != http.ErrServerClosed {
  154. log.Fatalf("服务运行失败: %v", err)
  155. }
  156. }()
  157. // 等待中断信号
  158. b.waitForServiceShutdown(service, shutdownHandler)
  159. }
  160. // waitForShutdown 等待关闭信号(关闭所有服务)
  161. func (b *Bootstrapper) waitForShutdown(handler ShutdownHandler) {
  162. log.Println("按 Ctrl+C 停止所有服务")
  163. // 等待信号
  164. <-b.quit
  165. log.Println("接收到终止信号,正在优雅关闭所有服务...")
  166. // 创建关闭上下文,给30秒完成当前请求
  167. ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
  168. defer cancel()
  169. // 关闭所有服务
  170. shutdownComplete := make(chan bool, len(b.services))
  171. for serviceName, service := range b.services {
  172. go func(name string, ws *WebService) {
  173. log.Printf("正在关闭服务: %s", name)
  174. if err := ws.HttpServer.Shutdown(ctx); err != nil {
  175. log.Printf("服务 %s 关闭失败: %v", name, err)
  176. } else {
  177. log.Printf("服务 %s 已关闭", name)
  178. }
  179. shutdownComplete <- true
  180. }(serviceName, service)
  181. }
  182. // 等待所有服务关闭完成
  183. for i := 0; i < len(b.services); i++ {
  184. <-shutdownComplete
  185. }
  186. // 执行关闭处理
  187. if handler != nil {
  188. handler.OnShutdown()
  189. }
  190. // 停止日志写入
  191. logger.StopESWriter()
  192. log.Println("所有服务优雅关闭完成")
  193. // 等待一小段时间确保日志写入完成
  194. time.Sleep(100 * time.Millisecond)
  195. os.Exit(0)
  196. }
  197. // waitForServiceShutdown 等待单个服务关闭
  198. func (b *Bootstrapper) waitForServiceShutdown(service *WebService, handler ShutdownHandler) {
  199. log.Printf("按 Ctrl+C 停止服务 %s", service.serviceName)
  200. // 等待信号
  201. <-service.quit
  202. log.Printf("接收到终止信号,正在优雅关闭服务 %s...", service.serviceName)
  203. // 创建关闭上下文,给30秒完成当前请求
  204. ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
  205. defer cancel()
  206. // 停止接收新请求,完成当前请求
  207. if err := service.HttpServer.Shutdown(ctx); err != nil {
  208. log.Printf("服务 %s 关闭失败: %v", service.serviceName, err)
  209. } else {
  210. log.Printf("服务 %s 已关闭", service.serviceName)
  211. }
  212. // 执行关闭处理
  213. if handler != nil {
  214. handler.OnShutdown()
  215. }
  216. // 停止日志写入
  217. logger.StopESWriter()
  218. log.Printf("服务 %s 优雅关闭完成", service.serviceName)
  219. // 等待一小段时间确保日志写入完成
  220. time.Sleep(100 * time.Millisecond)
  221. os.Exit(0)
  222. }
  223. // GetConfig 获取配置
  224. func (b *Bootstrapper) GetConfig() config.IConfig {
  225. return b.Cfg
  226. }
  227. // GetRouter 获取指定服务的路由器
  228. func (b *Bootstrapper) GetRouter(serviceName string) *http.ServeMux {
  229. service := b.CreateService(serviceName)
  230. return service.Router
  231. }
  232. // GetRouterDefault 获取第一个服务的路由器(兼容性方法)
  233. func (b *Bootstrapper) GetRouterDefault() *http.ServeMux {
  234. for _, service := range b.services {
  235. return service.Router
  236. }
  237. // 如果没有服务,创建默认路由器(向后兼容)
  238. return http.NewServeMux()
  239. }
  240. // Handle 注册路由处理器到指定服务
  241. func (b *Bootstrapper) Handle(serviceName, pattern string, handler http.Handler) bool {
  242. if service, exists := b.services[serviceName]; exists {
  243. service.Router.Handle(pattern, handler)
  244. return true
  245. }
  246. log.Printf("错误: 服务 %s 不存在", serviceName)
  247. return false
  248. }
  249. // SetShutdownHandler 为服务设置关闭处理器
  250. func (b *Bootstrapper) SetShutdownHandler(serviceName string, handler ShutdownHandler) bool {
  251. if service, exists := b.services[serviceName]; exists {
  252. service.shutdownHandler = handler
  253. return true
  254. }
  255. return false
  256. }
  257. // ========== WebService 的方法 ==========
  258. // GetServiceName 获取服务名称
  259. func (ws *WebService) GetServiceName() string {
  260. return ws.serviceName
  261. }
  262. // GetServiceConfig 获取服务配置
  263. func (ws *WebService) GetServiceConfig() *subconfigs.ServiceConfig {
  264. return ws.serviceConfig
  265. }
  266. // GetRouter 获取服务的路由器
  267. func (ws *WebService) GetRouter() *http.ServeMux {
  268. return ws.Router
  269. }
  270. // Handle 注册路由处理器
  271. func (ws *WebService) Handle(pattern string, handler http.Handler) {
  272. ws.Router.Handle(pattern, handler)
  273. }
  274. // SetShutdownHandler 设置关闭处理器
  275. func (ws *WebService) SetShutdownHandler(handler ShutdownHandler) {
  276. ws.shutdownHandler = handler
  277. }
  278. // Run 运行单个服务
  279. func (ws *WebService) Run(shutdownHandler ShutdownHandler) {
  280. log.Printf("服务 %s 开始运行...", ws.serviceConfig.ServiceName)
  281. // 设置信号监听
  282. signal.Notify(ws.quit, syscall.SIGINT, syscall.SIGTERM)
  283. // 启动服务
  284. go func() {
  285. log.Printf("服务器启动在 %s", ws.HttpServer.Addr)
  286. if err := ws.HttpServer.ListenAndServe(); err != nil && err != http.ErrServerClosed {
  287. log.Fatalf("服务 %s 运行失败: %v", ws.serviceName, err)
  288. }
  289. }()
  290. // 等待中断信号
  291. log.Printf("按 Ctrl+C 停止服务 %s", ws.serviceName)
  292. <-ws.quit
  293. log.Printf("接收到终止信号,正在优雅关闭服务 %s...", ws.serviceName)
  294. // 创建关闭上下文
  295. ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
  296. defer cancel()
  297. // 关闭服务
  298. if err := ws.HttpServer.Shutdown(ctx); err != nil {
  299. log.Printf("服务 %s 关闭失败: %v", ws.serviceName, err)
  300. } else {
  301. log.Printf("服务 %s 已关闭", ws.serviceName)
  302. }
  303. // 执行关闭处理
  304. if shutdownHandler != nil {
  305. shutdownHandler.OnShutdown()
  306. } else if ws.shutdownHandler != nil {
  307. ws.shutdownHandler.OnShutdown()
  308. }
  309. log.Printf("服务 %s 优雅关闭完成", ws.serviceName)
  310. time.Sleep(100 * time.Millisecond)
  311. os.Exit(0)
  312. }