feat(server): API relay gateway backend M0-M4
Gin + GORM + pure-Go SQLite. Users/auth (JWT), API key management with quotas, proxy gateway with weighted channel failover and health checks, usage/billing ledger, cross-protocol conversion (Anthropic Messages / OpenAI Chat Completions / OpenAI Responses), and channel/model admin API. Channels declare native API formats and auto-convert the rest. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
b0c7439c01
commit
d0e31b198f
@@ -0,0 +1,53 @@
|
||||
package channel
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"go.uber.org/zap"
|
||||
|
||||
"openteam/server/internal/store"
|
||||
)
|
||||
|
||||
// StartHealthCheck runs the periodic health-check loop in a goroutine.
|
||||
// Only channels that are enabled and have a bound test model are checked.
|
||||
func (s *Service) StartHealthCheck() {
|
||||
go func() {
|
||||
ticker := time.NewTicker(s.cfg.HealthCheck.Interval)
|
||||
defer ticker.Stop()
|
||||
s.runHealthCheck()
|
||||
for range ticker.C {
|
||||
s.runHealthCheck()
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
func (s *Service) runHealthCheck() {
|
||||
var channels []store.Channel
|
||||
if err := s.db.Where("enabled = ?", true).Find(&channels).Error; err != nil {
|
||||
s.log.Warn("health check query failed", zap.Error(err))
|
||||
return
|
||||
}
|
||||
for i := range channels {
|
||||
ch := &channels[i]
|
||||
// Skip channels already in cooldown until the cooldown elapses.
|
||||
if ch.HealthStatus == "cooldown" {
|
||||
continue
|
||||
}
|
||||
ok, _, _, err := s.Test(ch)
|
||||
if err != nil || !ok {
|
||||
s.MarkFailure(ch.ID)
|
||||
continue
|
||||
}
|
||||
s.MarkHealthy(ch.ID, "healthy")
|
||||
}
|
||||
}
|
||||
|
||||
// RecoverCooldown moves channels back from cooldown to degraded after the
|
||||
// cooldown window, giving them another chance to pass the health check.
|
||||
// Called periodically; keeps cooldown bounded.
|
||||
func (s *Service) RecoverCooldown() {
|
||||
cutoff := time.Now().Add(-s.cfg.HealthCheck.Cooldown)
|
||||
s.db.Model(&store.Channel{}).
|
||||
Where("health_status = ? AND updated_at < ?", "cooldown", cutoff).
|
||||
Updates(map[string]any{"health_status": "degraded", "health_failures": 0})
|
||||
}
|
||||
Reference in New Issue
Block a user