Files
stream.api/internal/service/service_health.go
lethdat a0ae2b681a feat: Implement video workflow repository and related services
- Added videoWorkflowRepository with methods to manage video and user interactions.
- Introduced catalog_mapper for converting database models to protobuf representations.
- Created domain_helpers for normalizing domain and ad format values.
- Defined service interfaces for payment, account, notification, domain, ad template, player config, video, and user management.
- Implemented OAuth helpers for generating state and caching keys.
- Developed payment_proto_helpers for mapping payment-related models to protobuf.
- Added service policy helpers to enforce plan requirements and user permissions.
- Created user_mapper for converting user payloads to protobuf format.
- Implemented value_helpers for handling various value conversions and nil checks.
- Developed video_helpers for normalizing video statuses and managing storage types.
- Created video_mapper for mapping video models to protobuf format.
- Implemented render workflow for managing video creation and job processing.
2026-03-26 18:38:47 +07:00

100 lines
3.2 KiB
Go

package service
import (
"context"
"fmt"
"time"
"github.com/redis/go-redis/v9"
"gorm.io/gorm"
)
type HealthStatus string
const (
HealthStatusHealthy HealthStatus = "healthy"
HealthStatusUnhealthy HealthStatus = "unhealthy"
HealthStatusDegraded HealthStatus = "degraded"
)
type ComponentHealth struct {
Status HealthStatus `json:"status"`
Message string `json:"message,omitempty"`
Latency string `json:"latency,omitempty"`
CheckedAt time.Time `json:"checked_at"`
}
type HealthReport struct {
Status HealthStatus `json:"status"`
Version string `json:"version"`
CheckedAt time.Time `json:"checked_at"`
Components map[string]ComponentHealth `json:"components"`
}
type HealthService struct {
db *gorm.DB
redis *redis.Client
version string
}
func NewHealthService(db *gorm.DB, redisClient *redis.Client, version string) *HealthService {
if version == "" {
version = "0.0.1"
}
return &HealthService{db: db, redis: redisClient, version: version}
}
func (s *HealthService) CheckHealth(ctx context.Context) *HealthReport {
report := &HealthReport{Status: HealthStatusHealthy, Version: s.version, CheckedAt: time.Now(), Components: map[string]ComponentHealth{}}
dbHealth := s.checkDatabase(ctx)
report.Components["database"] = dbHealth
if dbHealth.Status != HealthStatusHealthy {
report.Status = HealthStatusUnhealthy
}
redisHealth := s.checkRedis(ctx)
report.Components["redis"] = redisHealth
if redisHealth.Status != HealthStatusHealthy && report.Status == HealthStatusHealthy {
report.Status = HealthStatusDegraded
}
return report
}
func (s *HealthService) SimpleHealthCheck(ctx context.Context) (string, int) {
report := s.CheckHealth(ctx)
switch report.Status {
case HealthStatusHealthy:
return "ok", 200
case HealthStatusDegraded:
return "degraded", 200
default:
return "unhealthy", 503
}
}
func (s *HealthService) checkDatabase(ctx context.Context) ComponentHealth {
start := time.Now()
sqlDB, err := s.db.DB()
if err != nil {
return ComponentHealth{Status: HealthStatusUnhealthy, Message: fmt.Sprintf("failed to get database instance: %v", err), CheckedAt: time.Now()}
}
ctx, cancel := context.WithTimeout(ctx, 5*time.Second)
defer cancel()
if err := sqlDB.PingContext(ctx); err != nil {
return ComponentHealth{Status: HealthStatusUnhealthy, Message: fmt.Sprintf("database ping failed: %v", err), Latency: time.Since(start).String(), CheckedAt: time.Now()}
}
return ComponentHealth{Status: HealthStatusHealthy, Latency: time.Since(start).String(), CheckedAt: time.Now()}
}
func (s *HealthService) checkRedis(ctx context.Context) ComponentHealth {
start := time.Now()
if s.redis == nil {
return ComponentHealth{Status: HealthStatusUnhealthy, Message: "redis client not initialized", CheckedAt: time.Now()}
}
ctx, cancel := context.WithTimeout(ctx, 5*time.Second)
defer cancel()
if err := s.redis.Ping(ctx).Err(); err != nil {
return ComponentHealth{Status: HealthStatusUnhealthy, Message: fmt.Sprintf("redis ping failed: %v", err), Latency: time.Since(start).String(), CheckedAt: time.Now()}
}
return ComponentHealth{Status: HealthStatusHealthy, Latency: time.Since(start).String(), CheckedAt: time.Now()}
}