Files
uptimemonitor/store/check_store.go
2025-08-01 18:01:55 +02:00

141 lines
3.6 KiB
Go

package store
import (
"context"
"fmt"
"time"
"uptimemonitor"
"github.com/google/uuid"
)
func (s *Store) CreateCheck(ctx context.Context, check uptimemonitor.Check) (uptimemonitor.Check, error) {
stmt := `INSERT INTO checks(uuid, monitor_id, status_code, response_time_ms, created_at) VALUES(?, ?, ?, ?, ?)`
uuid := uuid.NewString()
if check.CreatedAt.IsZero() {
check.CreatedAt = time.Now()
}
tx, err := s.db.BeginTx(ctx, nil)
if err != nil {
return check, err
}
defer tx.Rollback()
res, err := tx.ExecContext(ctx, stmt, uuid, check.MonitorID, check.StatusCode, check.ResponseTimeMs, check.CreatedAt)
if err != nil {
return check, err
}
id, _ := res.LastInsertId()
check.ID = id
stmt = `
SELECT uptime, avg_response_time_ms, n, incidents_count
FROM monitors
WHERE id = ?
`
var n int64
var uptime float32
var avgResponseTimeMs int64
var incidentsCount int64
err = tx.QueryRowContext(ctx, stmt, check.MonitorID).Scan(&uptime, &avgResponseTimeMs, &n, &incidentsCount)
if err != nil {
return check, err
}
if check.StatusCode >= 300 {
incidentsCount++
}
stmt = `
UPDATE monitors
SET uptime = ?, avg_response_time_ms = ?, n = ?, incidents_count = ?
WHERE id = ?
`
newIncidentCount := incidentsCount
newN := n + 1
newUptime := fmt.Sprintf("%.1f", float32(float32(newN-newIncidentCount)/float32(newN)*float32(100)))
newAvgResponseTimeMs := (avgResponseTimeMs*n + check.ResponseTimeMs) / newN
_, err = tx.ExecContext(ctx, stmt, newUptime, newAvgResponseTimeMs, newN, newIncidentCount, check.MonitorID)
if err != nil {
return check, err
}
tx.Commit()
return check, nil
}
func (s *Store) ListChecks(ctx context.Context, monitorID int64, limit int) ([]uptimemonitor.Check, error) {
stmt := `
SELECT checks.id, checks.uuid, checks.monitor_id, checks.created_at,
checks.status_code, checks.response_time_ms,
monitors.id, monitors.uuid, monitors.url, monitors.created_at
FROM checks
LEFT JOIN monitors ON monitors.id = checks.monitor_id
WHERE monitor_id = ?
ORDER BY checks.id DESC
LIMIT ?
`
rows, err := s.db.QueryContext(ctx, stmt, monitorID, limit)
if err != nil {
return []uptimemonitor.Check{}, err
}
defer rows.Close()
var checks []uptimemonitor.Check
for rows.Next() {
var c uptimemonitor.Check
if err := rows.Scan(
&c.ID, &c.Uuid, &c.MonitorID, &c.CreatedAt,
&c.StatusCode, &c.ResponseTimeMs,
&c.Monitor.ID, &c.Monitor.Uuid, &c.Monitor.Url, &c.Monitor.CreatedAt,
); err != nil {
return []uptimemonitor.Check{}, err
}
checks = append(checks, c)
}
if err = rows.Err(); err != nil {
return []uptimemonitor.Check{}, err
}
return checks, nil
}
func (s *Store) GetCheckByID(ctx context.Context, id int64) (uptimemonitor.Check, error) {
stmt := `
SELECT
checks.id, checks.uuid, checks.monitor_id, checks.status_code, checks.response_time_ms, checks.created_at,
monitors.id, monitors.url, monitors.uuid, monitors.http_method, monitors.http_headers, monitors.http_body, monitors.created_at
FROM checks
LEFT JOIN monitors ON monitors.id = checks.monitor_id
WHERE checks.id = ?
`
var ch uptimemonitor.Check
err := s.db.QueryRowContext(ctx, stmt, id).Scan(
&ch.ID, &ch.Uuid, &ch.MonitorID, &ch.StatusCode, &ch.ResponseTimeMs, &ch.CreatedAt,
&ch.Monitor.ID, &ch.Monitor.Url, &ch.Monitor.Uuid, &ch.Monitor.HttpMethod, &ch.Monitor.HttpHeaders, &ch.Monitor.HttpBody, &ch.Monitor.CreatedAt,
)
return ch, err
}
func (s *Store) DeleteOldChecks(ctx context.Context) error {
stmt := `DELETE FROM checks WHERE created_at < ?`
_, err := s.db.ExecContext(ctx, stmt, time.Now().Add(-time.Hour))
return err
}