Files
tokens-reef/backend/internal/service/health_checker.go
User eb5d32553d
Some checks failed
CI / test (push) Has been cancelled
CI / golangci-lint (push) Has been cancelled
Security Scan / backend-security (push) Has been cancelled
Security Scan / frontend-security (push) Has been cancelled
feat: add webhook notification service and refactor data management
## Backend Changes
- Add WebhookService for sending alert notifications via HTTP webhooks
- Implement HMAC-SHA256 signature for webhook payload authentication
- Add webhook configuration API endpoints and settings
- Integrate webhook calls into OpsAlertEvaluatorService
- Fix routes/common.go string conversion (use strconv.Itoa)
- Add comprehensive webhook service tests

## Frontend Changes
- Add webhook notification configuration UI in OpsSettingsDialog
- Add WebhookNotificationConfig types and API functions
- Add i18n translations for webhook features (zh/en)
- Refactor DataManagementView.vue into modular components:
  - PostgresProfilesCard.vue (356 lines)
  - RedisProfilesCard.vue (331 lines)
  - S3ProfilesCard.vue (363 lines)
  - BackupJobsCard.vue (216 lines)
  - DataManagementView.vue (94 lines)
- Add OpsSettingsDialog component tests

## Testing
- All backend tests pass
- All frontend tests pass
- Webhook service tests cover signature, HTTP, timeout, error handling
2026-04-15 23:03:48 +08:00

131 lines
3.3 KiB
Go

package service
import (
"context"
"database/sql"
"time"
"github.com/redis/go-redis/v9"
)
// HealthChecker provides health check functionality for dependencies
type HealthChecker struct {
db *sql.DB
redisClient *redis.Client
}
// NewHealthChecker creates a new health checker instance
func NewHealthChecker(db *sql.DB, redisClient *redis.Client) *HealthChecker {
return &HealthChecker{
db: db,
redisClient: redisClient,
}
}
// CheckDatabase checks if the database connection is healthy
func (h *HealthChecker) CheckDatabase() bool {
if h.db == nil {
return false
}
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
defer cancel()
var result int
err := h.db.QueryRowContext(ctx, "SELECT 1").Scan(&result)
if err != nil {
return false
}
return result == 1
}
// CheckRedis checks if the Redis connection is healthy
func (h *HealthChecker) CheckRedis() bool {
if h.redisClient == nil {
return false
}
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
defer cancel()
err := h.redisClient.Ping(ctx).Err()
return err == nil
}
// GetDatabaseStats returns database connection statistics
func (h *HealthChecker) GetDatabaseStats() (active, idle int) {
if h.db == nil {
return 0, 0
}
stats := h.db.Stats()
return stats.InUse, stats.Idle
}
// GetRedisStats returns Redis connection statistics
func (h *HealthChecker) GetRedisStats() (total, idle int) {
if h.redisClient == nil {
return 0, 0
}
stats := h.redisClient.PoolStats()
if stats == nil {
return 0, 0
}
return int(stats.TotalConns), int(stats.IdleConns)
}
// HealthStatus represents the health status of all dependencies
type HealthStatus struct {
Database DatabaseHealth `json:"database"`
Redis RedisHealth `json:"redis"`
}
// DatabaseHealth represents database health information
type DatabaseHealth struct {
Healthy bool `json:"healthy"`
ActiveConns int `json:"active_connections"`
IdleConns int `json:"idle_connections"`
OpenConns int `json:"open_connections"`
MaxOpenConns int `json:"max_open_connections"`
WaitCount int64 `json:"wait_count"`
MaxIdleClosed int64 `json:"max_idle_closed"`
MaxLifetimeClosed int64 `json:"max_lifetime_closed"`
}
// RedisHealth represents Redis health information
type RedisHealth struct {
Healthy bool `json:"healthy"`
TotalConns int `json:"total_connections"`
IdleConns int `json:"idle_connections"`
}
// GetHealthStatus returns comprehensive health status
func (h *HealthChecker) GetHealthStatus() HealthStatus {
status := HealthStatus{}
// Database health
status.Database.Healthy = h.CheckDatabase()
if h.db != nil {
stats := h.db.Stats()
status.Database.ActiveConns = stats.InUse
status.Database.IdleConns = stats.Idle
status.Database.OpenConns = stats.OpenConnections
status.Database.MaxOpenConns = stats.MaxOpenConnections
status.Database.WaitCount = stats.WaitCount
status.Database.MaxIdleClosed = stats.MaxIdleClosed
status.Database.MaxLifetimeClosed = stats.MaxLifetimeClosed
}
// Redis health
status.Redis.Healthy = h.CheckRedis()
if h.redisClient != nil {
stats := h.redisClient.PoolStats()
if stats != nil {
status.Redis.TotalConns = int(stats.TotalConns)
status.Redis.IdleConns = int(stats.IdleConns)
}
}
return status
}