Files
Charon/backend/internal/models/uptime.go
GitHub Actions 209b2fc8e0 fix(monitoring): resolve uptime port mismatch for non-standard ports
Fixes uptime monitoring incorrectly using public URL port instead of
actual backend forward_port for TCP connectivity checks.

Changes:
- Add ProxyHost relationship to UptimeMonitor model
- Update checkHost() to use ProxyHost.ForwardPort
- Add Preload for ProxyHost in getAllMonitors()
- Add diagnostic logging for port resolution

This fixes false "down" status for services like Wizarr that use
non-standard backend ports (5690) while exposing standard HTTPS (443).

Testing:
- Wizarr now shows as "up" (was incorrectly "down")
- All 16 monitors working correctly
- Backend coverage: 85.5%
- No regressions in other uptime checks

Resolves: Wizarr uptime monitoring false negative
2025-12-23 03:28:45 +00:00

56 lines
2.2 KiB
Go

package models
import (
"time"
"github.com/google/uuid"
"gorm.io/gorm"
)
type UptimeMonitor struct {
ID string `gorm:"primaryKey" json:"id"`
ProxyHostID *uint `json:"proxy_host_id" gorm:"index"` // Optional link to proxy host
ProxyHost *ProxyHost `json:"proxy_host,omitempty" gorm:"foreignKey:ProxyHostID"` // Relationship for automatic loading
RemoteServerID *uint `json:"remote_server_id" gorm:"index"` // Optional link to remote server
UptimeHostID *string `json:"uptime_host_id" gorm:"index"` // Link to parent host for grouping
Name string `json:"name" gorm:"index"`
Type string `json:"type"` // http, tcp, ping
URL string `json:"url"`
UpstreamHost string `json:"upstream_host" gorm:"index"` // The actual backend host/IP (for grouping)
Interval int `json:"interval"` // seconds
Enabled bool `json:"enabled" gorm:"index"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
// Current Status (Cached)
Status string `json:"status" gorm:"index"` // up, down, maintenance, pending
LastCheck time.Time `json:"last_check"`
Latency int64 `json:"latency"` // ms
FailureCount int `json:"failure_count"`
LastStatusChange time.Time `json:"last_status_change"`
MaxRetries int `json:"max_retries" gorm:"default:3"`
// Notification tracking
LastNotifiedDown time.Time `json:"last_notified_down"` // Prevent duplicate notifications
NotifiedInBatch bool `json:"notified_in_batch"` // Was this included in a batch notification?
}
type UptimeHeartbeat struct {
ID uint `gorm:"primaryKey" json:"id"`
MonitorID string `json:"monitor_id" gorm:"index"`
Status string `json:"status"` // up, down
Latency int64 `json:"latency"`
Message string `json:"message"`
CreatedAt time.Time `json:"created_at" gorm:"index"`
}
func (m *UptimeMonitor) BeforeCreate(tx *gorm.DB) (err error) {
if m.ID == "" {
m.ID = uuid.New().String()
}
if m.Status == "" {
m.Status = "pending"
}
return
}