- 3.1 bcrypt 移出事务 (Register): repository.HashPassword 前移到 db.Transaction 之前。 - 3.2 Login 消除用户枚举 + 限流 + timing 抹平: pkg/errors 加 ErrInvalidCredential / ErrTooManyLoginAttempts; user-not-found 跑 dummy bcrypt 抹平 ~100ms 时序差; mobile 5次/ip 20次 per 15min 限流 (Redis, fail-open 降级)。 - 3.3 MQ streams adapter 停用 → stub: 0 业务调用方, noop EventProducer.Publish; Init 不再装配 streams; 11 处硬编码 'gallery'/'default' 抽常量到 pkg/queue/consts (值不变, 消漂移)。 - 3.5 JWT 密钥治理: pkg/jwt MustInit fail-fast + atomic.Value, 50-goroutine race_test 零告警; MustInit 调用点 gateway main + auth_provider + loadgen 同步更新。 - 3.6 aiChat 健壮性: SaveContext 用 persona.ID(非 req.PersonaId); Redis/memory 错误 记 WARN 不静默; Dify err 映射稳定用户文案。 - 3.7 statistic.Client 重构: TrackEvent 改 buffered channel (cap 1024) + dispatchLoop worker。 - 3.8 网关聚合: StarCache (60s TTL, singleflight) 替换 GetFanIdentities 链式调用; DeleteAccount 改网关直调 userService.DeleteAccount(避免改 hand-written triple.go); 铸造双写改异步 channel+consumer (3 retry)。 - 大量单测: 各子项 TDD (RED→GREEN), 关键并发 race_test (50 goroutine)。 - .env.example JWT_SECRET 改为 ≥32 字节 base64 示例(原为空, 被 MustInit 立即拒)。 Co-Authored-By: Claude <noreply@anthropic.com>
64 lines
1.5 KiB
Go
64 lines
1.5 KiB
Go
package health
|
|
|
|
import (
|
|
"fmt"
|
|
"log"
|
|
"net/http"
|
|
"sync"
|
|
)
|
|
|
|
// Handler 健康检查处理器
|
|
type Handler struct {
|
|
serviceName string
|
|
port int
|
|
server *http.Server
|
|
wg sync.WaitGroup
|
|
}
|
|
|
|
// NewHandler 创建健康检查处理器
|
|
func NewHandler(serviceName string, port int) *Handler {
|
|
return &Handler{
|
|
serviceName: serviceName,
|
|
port: port,
|
|
}
|
|
}
|
|
|
|
// Start 启动健康检查 HTTP 服务器
|
|
func (h *Handler) Start() {
|
|
mux := http.NewServeMux()
|
|
mux.HandleFunc("/health", h.handleHealth)
|
|
// /healthz alias for K8s probe convention; canonical path stays /health.
|
|
mux.HandleFunc("/healthz", h.handleHealth)
|
|
|
|
h.server = &http.Server{
|
|
Addr: fmt.Sprintf(":%d", h.port),
|
|
Handler: mux,
|
|
}
|
|
|
|
h.wg.Add(1)
|
|
go func() {
|
|
defer h.wg.Done()
|
|
log.Printf("[%s] Health check server started on port %d", h.serviceName, h.port)
|
|
if err := h.server.ListenAndServe(); err != nil && err != http.ErrServerClosed {
|
|
log.Printf("[%s] Health check server error: %v", h.serviceName, err)
|
|
}
|
|
}()
|
|
}
|
|
|
|
// Stop 停止健康检查 HTTP 服务器
|
|
func (h *Handler) Stop() {
|
|
if h.server != nil {
|
|
if err := h.server.Close(); err != nil {
|
|
log.Printf("[%s] Health check server close error: %v", h.serviceName, err)
|
|
}
|
|
}
|
|
h.wg.Wait()
|
|
log.Printf("[%s] Health check server stopped", h.serviceName)
|
|
}
|
|
|
|
func (h *Handler) handleHealth(w http.ResponseWriter, r *http.Request) {
|
|
w.WriteHeader(http.StatusOK)
|
|
w.Header().Set("Content-Type", "application/json")
|
|
fmt.Fprintf(w, `{"status":"ok","service":"%s"}`, h.serviceName)
|
|
}
|