initial commit

This commit is contained in:
m.zare
2026-04-10 18:25:21 +03:30
commit 77ca6c34a3
263 changed files with 34470 additions and 0 deletions

9
pkg/health/const.go Normal file
View File

@@ -0,0 +1,9 @@
package health
type Status string
const (
StatusHealthy Status = "healthy"
StatusUnhealthy Status = "unhealthy"
StatusDegraded Status = "degraded"
)

82
pkg/health/health.go Normal file
View File

@@ -0,0 +1,82 @@
package health
import (
"context"
"sync"
"time"
)
type (
Checker func(ctx context.Context) HealthCheck
HealthCheck struct {
Name string `json:"name"`
Status Status `json:"status"`
Message string `json:"message,omitempty"`
Timestamp time.Time `json:"timestamp"`
Duration time.Duration `json:"duration"`
Details map[string]interface{} `json:"details,omitempty"`
}
HealthResponse struct {
Status Status `json:"status"`
Timestamp time.Time `json:"timestamp"`
Version string `json:"version"`
Checks map[string]HealthCheck `json:"checks"`
Details map[string]interface{} `json:"details,omitempty"`
}
)
func Health(ctx context.Context, version string, checkers ...Checker) HealthResponse {
start := time.Now()
results := make(map[string]HealthCheck, len(checkers))
wg := sync.WaitGroup{}
mu := sync.Mutex{}
wg.Add(len(checkers))
for _, checker := range checkers {
go func(c Checker) {
defer wg.Done()
check := c(ctx)
mu.Lock()
results[check.Name] = check
mu.Unlock()
}(checker)
}
wg.Wait()
// Determine overall status
overallStatus := determineOverallStatus(results)
return HealthResponse{
Status: overallStatus,
Timestamp: time.Now(),
Version: version,
Checks: results,
Details: map[string]interface{}{
"uptime": time.Since(start).String(),
},
}
}
func determineOverallStatus(checks map[string]HealthCheck) Status {
var unhealthyCount, degradedCount int
for _, c := range checks {
switch c.Status {
case StatusUnhealthy:
unhealthyCount++
case StatusDegraded:
degradedCount++
}
}
switch {
case unhealthyCount > 0:
return StatusUnhealthy
case degradedCount > 0:
return StatusDegraded
default:
return StatusHealthy
}
}

113
pkg/health/infra_checker.go Normal file
View File

@@ -0,0 +1,113 @@
package health
import (
"context"
"github.com/redis/go-redis/v9"
"gorm.io/gorm"
rabbitmq "base/pkg/rabbit"
"time"
)
func DatabaseHealthChecker(db *gorm.DB) Checker {
return func(ctx context.Context) HealthCheck {
start := time.Now()
check := HealthCheck{
Name: "database",
Timestamp: time.Now(),
}
// Perform health check
sqlDB, err := db.DB()
if err != nil {
check.Status = StatusUnhealthy
check.Message = "Failed to get database connection: " + err.Error()
check.Duration = time.Since(start)
return check
}
err = sqlDB.PingContext(ctx)
if err != nil {
check.Status = StatusUnhealthy
check.Message = "Database ping failed: " + err.Error()
check.Duration = time.Since(start)
return check
}
check.Status = StatusHealthy
check.Message = "Database connection is healthy"
check.Duration = time.Since(start)
check.Details = map[string]interface{}{
"connected": true,
}
return check
}
}
func RabbitMQHealthChecker(rabbitmq rabbitmq.Client) Checker {
return func(ctx context.Context) HealthCheck {
start := time.Now()
check := HealthCheck{
Name: "rabbitmq",
Timestamp: time.Now(),
}
// Perform health check
err := rabbitmq.HealthCheck()
if err != nil {
check.Status = StatusUnhealthy
check.Message = "RabbitMQ health check failed: " + err.Error()
check.Duration = time.Since(start)
return check
}
check.Status = StatusHealthy
check.Message = "RabbitMQ connection is healthy"
check.Duration = time.Since(start)
check.Details = map[string]interface{}{
"connected": true,
}
return check
}
}
func RedisHealthChecker(redis *redis.Client) Checker {
return func(ctx context.Context) HealthCheck {
start := time.Now()
check := HealthCheck{
Name: "redis",
Timestamp: time.Now(),
}
// Perform health check
ctx, cancel := context.WithTimeout(ctx, 5*time.Second)
defer cancel()
_, err := redis.Ping(ctx).Result()
if err != nil {
check.Status = StatusUnhealthy
check.Message = "Redis ping failed: " + err.Error()
check.Duration = time.Since(start)
return check
}
// Get Redis info
info, err := redis.Info(ctx, "server", "clients", "memory", "stats").Result()
if err != nil {
check.Status = StatusDegraded
check.Message = "Redis is responding but info command failed: " + err.Error()
check.Duration = time.Since(start)
return check
}
check.Status = StatusHealthy
check.Message = "Redis connection is healthy"
check.Duration = time.Since(start)
check.Details = map[string]interface{}{
"info": info,
}
return check
}
}