Przeglądaj źródła

Release v0.1.1222

qdy 2 miesięcy temu
commit
b52e1f56e8
3 zmienionych plików z 262 dodań i 33 usunięć
  1. 21
    21
      bootstraps/bootstrap.go
  2. 85
    12
      consul/register_consul.go
  3. 156
    0
      webx/health_handle.go

+ 21
- 21
bootstraps/bootstrap.go Wyświetl plik

225
 		go func(name string, ws *WebService) {
225
 		go func(name string, ws *WebService) {
226
 			log.Printf("正在关闭服务: %s", name)
226
 			log.Printf("正在关闭服务: %s", name)
227
 			//退出注册中心
227
 			//退出注册中心
228
-			consul.Deregister(service.serviceName, service.Ip, service.Port)
228
+			consul.Deregister(service.serviceName, service.Ip, service.Port, b.Cfg.GetConsulConfig())
229
 
229
 
230
 			if err := ws.HttpServer.Shutdown(ctx); err != nil {
230
 			if err := ws.HttpServer.Shutdown(ctx); err != nil {
231
 				log.Printf("服务 %s 关闭失败: %v", name, err)
231
 				log.Printf("服务 %s 关闭失败: %v", name, err)
265
 	log.Printf("接收到终止信号,正在优雅关闭服务 %s...", service.serviceName)
265
 	log.Printf("接收到终止信号,正在优雅关闭服务 %s...", service.serviceName)
266
 
266
 
267
 	//退出注册中心
267
 	//退出注册中心
268
-	consul.Deregister(service.serviceName, service.Ip, service.Port)
268
+	consul.Deregister(service.serviceName, service.Ip, service.Port, b.Cfg.GetConsulConfig())
269
 
269
 
270
 	// 创建关闭上下文,给30秒完成当前请求
270
 	// 创建关闭上下文,给30秒完成当前请求
271
 	ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
271
 	ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
297
 	return b.Cfg
297
 	return b.Cfg
298
 }
298
 }
299
 
299
 
300
-// GetRouter 获取指定服务的路由器
300
+// GetWebService 获取指定服务的路由器
301
 func (b *Bootstrapper) GetRouter(yamlNode string) *http.ServeMux {
301
 func (b *Bootstrapper) GetRouter(yamlNode string) *http.ServeMux {
302
 	service := b.createService(yamlNode)
302
 	service := b.createService(yamlNode)
303
 	return service.Router
303
 	return service.Router
312
 	return http.NewServeMux()
312
 	return http.NewServeMux()
313
 }
313
 }
314
 
314
 
315
-// Handle 注册路由处理器到指定服务
316
-func (b *Bootstrapper) Handle(serviceName, pattern string, handler http.Handler) bool {
317
-	if service, exists := b.services[serviceName]; exists {
318
-		service.Router.Handle(pattern, handler)
319
-		return true
320
-	}
321
-	log.Printf("错误: 服务 %s 不存在", serviceName)
322
-	return false
323
-}
315
+// // Handle 注册路由处理器到指定服务
316
+// func (b *Bootstrapper) Handle(serviceName, pattern string, handler http.Handler) bool {
317
+// 	if service, exists := b.services[serviceName]; exists {
318
+// 		service.Router.Handle(pattern, handler)
319
+// 		return true
320
+// 	}
321
+// 	log.Printf("错误: 服务 %s 不存在", serviceName)
322
+// 	return false
323
+// }
324
 
324
 
325
 // SetShutdownHandler 为服务设置关闭处理器
325
 // SetShutdownHandler 为服务设置关闭处理器
326
 func (b *Bootstrapper) SetShutdownHandler(serviceName string, handler ShutdownHandler) bool {
326
 func (b *Bootstrapper) SetShutdownHandler(serviceName string, handler ShutdownHandler) bool {
334
 // ========== WebService 的方法 ==========
334
 // ========== WebService 的方法 ==========
335
 
335
 
336
 // GetServiceName 获取服务名称
336
 // GetServiceName 获取服务名称
337
-func (ws *WebService) GetServiceName() string {
338
-	return ws.serviceName
339
-}
337
+// func (ws *WebService) GetServiceName() string {
338
+// 	return ws.serviceName
339
+// }
340
 
340
 
341
 // // GetServiceConfig 获取服务配置
341
 // // GetServiceConfig 获取服务配置
342
 // func (ws *WebService) GetServiceConfig() *subconfigs.ServiceConfig {
342
 // func (ws *WebService) GetServiceConfig() *subconfigs.ServiceConfig {
344
 // }
344
 // }
345
 
345
 
346
 // GetRouter 获取服务的路由器
346
 // GetRouter 获取服务的路由器
347
-func (ws *WebService) GetRouter() *http.ServeMux {
348
-	return ws.Router
349
-}
347
+// func (ws *WebService) GetRouter() *http.ServeMux {
348
+// 	return ws.Router
349
+// }
350
 
350
 
351
 // Handle 注册路由处理器
351
 // Handle 注册路由处理器
352
-func (ws *WebService) Handle(pattern string, handler http.Handler) {
353
-	ws.Router.Handle(pattern, handler)
354
-}
352
+// func (ws *WebService) Handle(pattern string, handler http.Handler) {
353
+// 	ws.Router.Handle(pattern, handler)
354
+// }
355
 
355
 
356
 // SetShutdownHandler 设置关闭处理器
356
 // SetShutdownHandler 设置关闭处理器
357
 func (ws *WebService) SetShutdownHandler(handler ShutdownHandler) {
357
 func (ws *WebService) SetShutdownHandler(handler ShutdownHandler) {

+ 85
- 12
consul/register_consul.go Wyświetl plik

4
 import (
4
 import (
5
 	"fmt"
5
 	"fmt"
6
 	"log"
6
 	"log"
7
+	"time"
7
 
8
 
8
 	"git.x2erp.com/qdy/go-base/client"
9
 	"git.x2erp.com/qdy/go-base/client"
9
 	"git.x2erp.com/qdy/go-base/config/subconfigs"
10
 	"git.x2erp.com/qdy/go-base/config/subconfigs"
20
 	apiConfig := api.DefaultConfig()
21
 	apiConfig := api.DefaultConfig()
21
 	if consulConfig.Address != "" {
22
 	if consulConfig.Address != "" {
22
 		apiConfig.Address = consulConfig.Address
23
 		apiConfig.Address = consulConfig.Address
24
+		log.Printf("使用Consul地址: %s", consulConfig.Address)
25
+	} else {
26
+		log.Printf("⚠️ 使用默认Consul地址: %s", apiConfig.Address)
23
 	}
27
 	}
28
+
24
 	if consulConfig.Token != "" {
29
 	if consulConfig.Token != "" {
25
 		apiConfig.Token = consulConfig.Token
30
 		apiConfig.Token = consulConfig.Token
26
 	}
31
 	}
34
 		return fmt.Errorf("创建Consul客户端失败: %v", err)
39
 		return fmt.Errorf("创建Consul客户端失败: %v", err)
35
 	}
40
 	}
36
 
41
 
37
-	// 4. 注册服务
42
+	// 4. 测试连接
43
+	_, err = client.Agent().Self()
44
+	if err != nil {
45
+		return fmt.Errorf("无法连接到Consul服务器 %s: %v", apiConfig.Address, err)
46
+	}
47
+	log.Printf("✅ 成功连接到Consul服务器: %s", apiConfig.Address)
48
+
49
+	// 5. 注册服务(完整健康检查配置)
38
 	registration := &api.AgentServiceRegistration{
50
 	registration := &api.AgentServiceRegistration{
39
 		ID:      fmt.Sprintf("%s-%s-%d", serviceName, ip, port),
51
 		ID:      fmt.Sprintf("%s-%s-%d", serviceName, ip, port),
40
 		Name:    serviceName,
52
 		Name:    serviceName,
41
 		Address: ip,
53
 		Address: ip,
42
 		Port:    port,
54
 		Port:    port,
55
+		Tags:    []string{"http", "microservice"},
43
 		Check: &api.AgentServiceCheck{
56
 		Check: &api.AgentServiceCheck{
44
-			HTTP:     fmt.Sprintf("http://%s:%d/health", ip, port),
45
-			Interval: "10s",
57
+			HTTP:                           fmt.Sprintf("http://%s:%d/health", ip, port),
58
+			Interval:                       "10s",
59
+			Timeout:                        "5s",      // 关键:设置超时
60
+			DeregisterCriticalServiceAfter: "1m",      // 关键:失败后注销时间
61
+			TLSSkipVerify:                  true,      // 跳过TLS验证
62
+			Status:                         "passing", // 初始状态
63
+		},
64
+		Meta: map[string]string{
65
+			"registered_at": time.Now().Format(time.RFC3339),
66
+			"port":          fmt.Sprintf("%d", port),
46
 		},
67
 		},
47
 	}
68
 	}
48
 
69
 
51
 		return fmt.Errorf("consul注册失败: %v", err)
72
 		return fmt.Errorf("consul注册失败: %v", err)
52
 	}
73
 	}
53
 
74
 
75
+	// 打印详细注册信息
54
 	log.Printf("✅ 服务已注册到Consul服务器: %s", consulConfig.Address)
76
 	log.Printf("✅ 服务已注册到Consul服务器: %s", consulConfig.Address)
77
+	log.Printf("📋 注册详情:")
78
+	log.Printf("   服务名称: %s", serviceName)
79
+	log.Printf("   服务地址: %s:%d", ip, port)
80
+	log.Printf("   服务ID: %s", registration.ID)
81
+	log.Printf("   健康检查: %s", registration.Check.HTTP)
82
+	log.Printf("   检查间隔: %s", registration.Check.Interval)
83
+	log.Printf("   检查超时: %s", registration.Check.Timeout)
84
+	log.Printf("   失败注销: %s", registration.Check.DeregisterCriticalServiceAfter)
85
+
55
 	return nil
86
 	return nil
56
 }
87
 }
57
 
88
 
89
+// CheckRegistration 检查服务是否已注册
90
+func CheckRegistration(serviceName, configHostname string, port int, consulConfig *subconfigs.ConsulConfig) error {
91
+	ip := client.GetServiceIP(configHostname)
92
+	serviceID := fmt.Sprintf("%s-%s-%d", serviceName, ip, port)
93
+
94
+	// 创建客户端
95
+	apiConfig := api.DefaultConfig()
96
+	if consulConfig.Address != "" {
97
+		apiConfig.Address = consulConfig.Address
98
+	}
99
+	client, err := api.NewClient(apiConfig)
100
+	if err != nil {
101
+		return fmt.Errorf("创建Consul客户端失败: %v", err)
102
+	}
103
+
104
+	// 检查服务
105
+	services, err := client.Agent().Services()
106
+	if err != nil {
107
+		return fmt.Errorf("获取服务列表失败: %v", err)
108
+	}
109
+
110
+	if svc, exists := services[serviceID]; exists {
111
+		log.Printf("✅ 服务已注册:")
112
+		log.Printf("   服务ID: %s", svc.ID)
113
+		log.Printf("   服务名: %s", svc.Service)
114
+		log.Printf("   地址: %s:%d", svc.Address, svc.Port)
115
+
116
+		// 检查健康状态
117
+		checks, err := client.Agent().Checks()
118
+		if err == nil {
119
+			for checkID, check := range checks {
120
+				if check.ServiceID == serviceID {
121
+					log.Printf("   健康检查[%s]: %s", checkID, check.Status)
122
+				}
123
+			}
124
+		}
125
+		return nil
126
+	}
127
+
128
+	return fmt.Errorf("服务未注册: %s", serviceID)
129
+}
130
+
58
 // Deregister 注销服务
131
 // Deregister 注销服务
59
-// Deregister 注销服务
60
-func Deregister(serviceName, ip string, port int) {
61
-	// 获取IP
62
-	//ip := netutil.GetServiceIP(configHostname)
132
+func Deregister(serviceName, ip string, port int, consulConfig *subconfigs.ConsulConfig) error {
63
 	serviceID := fmt.Sprintf("%s-%s-%d", serviceName, ip, port)
133
 	serviceID := fmt.Sprintf("%s-%s-%d", serviceName, ip, port)
64
 
134
 
65
 	// 创建客户端
135
 	// 创建客户端
66
-	client, err := api.NewClient(api.DefaultConfig())
136
+	apiConfig := api.DefaultConfig()
137
+	if consulConfig != nil && consulConfig.Address != "" {
138
+		apiConfig.Address = consulConfig.Address
139
+	}
140
+	client, err := api.NewClient(apiConfig)
67
 	if err != nil {
141
 	if err != nil {
68
-		log.Printf("创建consul客户端失败: %v", err)
69
-		return
142
+		return fmt.Errorf("创建consul客户端失败: %v", err)
70
 	}
143
 	}
71
 
144
 
72
 	// 注销服务
145
 	// 注销服务
73
 	err = client.Agent().ServiceDeregister(serviceID)
146
 	err = client.Agent().ServiceDeregister(serviceID)
74
 	if err != nil {
147
 	if err != nil {
75
-		log.Printf("从consul注销服务失败 (ID: %s): %v", serviceID, err)
76
-		return
148
+		return fmt.Errorf("从consul注销服务失败 (ID: %s): %v", serviceID, err)
77
 	}
149
 	}
78
 
150
 
79
 	log.Printf("✅ 已从consul注销服务: %s", serviceID)
151
 	log.Printf("✅ 已从consul注销服务: %s", serviceID)
152
+	return nil
80
 }
153
 }

+ 156
- 0
webx/health_handle.go Wyświetl plik

1
+// webx/health_util.go
2
+package webx
3
+
4
+import (
5
+	"time"
6
+
7
+	"git.x2erp.com/qdy/go-base/config"
8
+	"git.x2erp.com/qdy/go-base/logger"
9
+)
10
+
11
+// HealthResponse 健康检查响应
12
+type HealthResponse struct {
13
+	Status    string                 `json:"status"`
14
+	Service   string                 `json:"service"`
15
+	Version   string                 `json:"version,omitempty"`
16
+	Env       string                 `json:"env,omitempty"`
17
+	Message   string                 `json:"message,omitempty"`
18
+	Timestamp string                 `json:"timestamp,omitempty"`
19
+	Data      map[string]interface{} `json:"data,omitempty"`
20
+}
21
+
22
+// RegisterDefaultHealthCheck 注册默认健康检查路由(带详细日志)
23
+func RegisterDefaultHealthCheck(ws *WebService, serviceName string) {
24
+	if serviceName == "" {
25
+		cfg, _ := config.GetConfig()
26
+		serviceName = cfg.GetAppName()
27
+		if serviceName == "" {
28
+			serviceName = "unknown-service"
29
+		}
30
+	}
31
+
32
+	logger.Debug("注册健康检查路由,服务名: %s", serviceName)
33
+
34
+	// 健康检查(带详细日志)
35
+	ws.GET("/health", func() (HealthResponse, error) {
36
+		logger.Debug("健康检查被调用: /health")
37
+
38
+		cfg, _ := config.GetConfig()
39
+		response := HealthResponse{
40
+			Status:    "ok",
41
+			Service:   serviceName,
42
+			Version:   cfg.GetAppVersion(),
43
+			Env:       cfg.GetAppEnv(),
44
+			Timestamp: time.Now().Format(time.RFC3339),
45
+		}
46
+
47
+		logger.Debug("健康检查响应: %+v", response)
48
+		return response, nil
49
+	}).Desc("健康检查").Register()
50
+
51
+	// 就绪检查
52
+	ws.GET("/health/ready", func() (HealthResponse, error) {
53
+		logger.Debug("就绪检查被调用: /health/ready")
54
+
55
+		return HealthResponse{
56
+			Status:    "ready",
57
+			Service:   serviceName,
58
+			Timestamp: time.Now().Format(time.RFC3339),
59
+		}, nil
60
+	}).Desc("就绪检查").Register()
61
+
62
+	// 存活检查
63
+	ws.GET("/health/live", func() (HealthResponse, error) {
64
+		logger.Debug("存活检查被调用: /health/live")
65
+
66
+		return HealthResponse{
67
+			Status:    "alive",
68
+			Service:   serviceName,
69
+			Timestamp: time.Now().Format(time.RFC3339),
70
+		}, nil
71
+	}).Desc("存活检查").Register()
72
+
73
+	// 服务信息
74
+	ws.GET("/health/info", func() (map[string]interface{}, error) {
75
+		logger.Debug("服务信息被调用: /health/info")
76
+
77
+		cfg, _ := config.GetConfig()
78
+		response := map[string]interface{}{
79
+			"service":     serviceName,
80
+			"version":     cfg.GetAppVersion(),
81
+			"environment": cfg.GetAppEnv(),
82
+			"timestamp":   time.Now().Format(time.RFC3339),
83
+			"endpoints": map[string]string{
84
+				"health": "/health",
85
+				"ready":  "/health/ready",
86
+				"live":   "/health/live",
87
+				"info":   "/health/info",
88
+			},
89
+			"config_info": map[string]string{
90
+				"app_name":    cfg.GetAppName(),
91
+				"app_version": cfg.GetAppVersion(),
92
+				"app_env":     cfg.GetAppEnv(),
93
+			},
94
+		}
95
+
96
+		logger.Debug("服务信息响应: %+v", response)
97
+		return response, nil
98
+	}).Desc("服务信息").Register()
99
+
100
+	logger.Debug("健康检查路由注册完成,路径: /health, /health/ready, /health/live, /health/info")
101
+}
102
+
103
+// RegisterConsulHealthCheck 注册Consul兼容的健康检查
104
+func RegisterConsulHealthCheck(ws *WebService) {
105
+	logger.Debug("注册Consul兼容健康检查路由")
106
+
107
+	// Consul需要的健康检查端点(返回text/plain)
108
+	ws.GET("/health", func() ([]byte, error) {
109
+		logger.Info("Consul健康检查被调用: /health")
110
+		logger.Info("返回 'OK' 给Consul")
111
+		return []byte("OK"), nil
112
+	}).Desc("Consul健康检查").Register()
113
+
114
+	// Consul详细状态检查
115
+	ws.GET("/health/consul", func() (map[string]interface{}, error) {
116
+		logger.Debug("Consul状态检查被调用: /health/consul")
117
+
118
+		cfg, _ := config.GetConfig()
119
+		response := map[string]interface{}{
120
+			"status":  "passing",
121
+			"service": cfg.GetAppName(),
122
+			"output":  "Service is healthy",
123
+			"checks": map[string]interface{}{
124
+				"service:health": map[string]string{
125
+					"status": "passing",
126
+				},
127
+			},
128
+		}
129
+
130
+		logger.Debug("Consul健康状态响应: %+v", response)
131
+		return response, nil
132
+	}).Desc("Consul健康状态").Register()
133
+}
134
+
135
+// RegisterAllHealthChecks 注册所有健康检查(推荐使用)
136
+func RegisterAllHealthChecks(ws *WebService, serviceName string) {
137
+	logger.Debug("开始注册所有健康检查路由...")
138
+
139
+	// 注册默认健康检查
140
+	RegisterDefaultHealthCheck(ws, serviceName)
141
+
142
+	// 注册Consul兼容检查
143
+	RegisterConsulHealthCheck(ws)
144
+
145
+	// 添加一个简单的ping端点(很多监控系统需要)
146
+	ws.GET("/ping", func() (map[string]interface{}, error) {
147
+		logger.Debug("Ping端点被调用: /ping")
148
+		return map[string]interface{}{
149
+			"ping":    "pong",
150
+			"time":    time.Now().Unix(),
151
+			"service": serviceName,
152
+		}, nil
153
+	}).Desc("简单Ping检查").Register()
154
+
155
+	logger.Debug("所有健康检查路由注册完成")
156
+}

Ładowanie…
Anuluj
Zapisz