Simple homelab monitoring service
0

Configure Feed

Select the types of activity you want to include in your feed.

Add 'enabled' column to services table and update model/tests

Chris Walker (Jun 23, 2026, 9:41 PM +0100) a8a18ab3 ccffa6c9

+57 -48
+6 -5
db/services.go
··· 24 24 for hdr, val := range s.Headers { 25 25 headers = append(headers, fmt.Sprintf("%s,%s", hdr, val)) 26 26 } 27 - values[i] = fmt.Sprintf("('%s','%s','%s')", 27 + values[i] = fmt.Sprintf("('%s','%s','%s','%t')", 28 28 s.Name, 29 29 s.URL, 30 - strings.Join(headers, "|")) 30 + strings.Join(headers, "|"), 31 + s.Enabled) 31 32 } 32 33 33 - stmt := fmt.Sprintf("INSERT INTO services (NAME, URL, HEADERS) VALUES %s", 34 + stmt := fmt.Sprintf("INSERT INTO services (name, url, headers, enabled) VALUES %s", 34 35 strings.Join(values, ",")) 35 36 _, err = tx.Exec(stmt) 36 37 if err != nil { ··· 57 58 var svc models.Service 58 59 59 60 var headers string 60 - err := rows.Scan(&svc.ID, &svc.Name, &svc.URL, &headers) 61 + err := rows.Scan(&svc.ID, &svc.Name, &svc.URL, &headers, &svc.Enabled) 61 62 if err != nil { 62 63 return nil, err 63 64 } ··· 77 78 var svc models.Service 78 79 79 80 var headers string 80 - if err := row.Scan(&svc.ID, &svc.Name, &svc.URL, &headers); err != nil { 81 + if err := row.Scan(&svc.ID, &svc.Name, &svc.URL, &headers, &svc.Enabled); err != nil { 81 82 if err == sql.ErrNoRows { 82 83 return nil, fmt.Errorf("no service with id [%d]: %w", id, ErrNotFound) 83 84 }
+7 -4
db/services_test.go
··· 16 16 "basic": { 17 17 services: []models.Service{ 18 18 { 19 - Name: "service_a", 20 - URL: "http://a.example.com", 19 + Name: "service_a", 20 + URL: "http://a.example.com", 21 + Enabled: true, 21 22 }, 22 23 { 23 24 Name: "service_b", ··· 26 27 "header-a": "value-a", 27 28 "header-b": "value-b", 28 29 }, 30 + Enabled: true, 29 31 }, 30 32 { 31 - Name: "service_c", 32 - URL: "http://c.example.com", 33 + Name: "service_c", 34 + URL: "http://c.example.com", 35 + Enabled: false, 33 36 }, 34 37 }, 35 38 },
+2 -1
db/sql/schema.sql
··· 8 8 id INTEGER PRIMARY KEY, 9 9 name TEXT NOT NULL, 10 10 url TEXT NOT NULL, 11 - headers TEXT 11 + headers TEXT, 12 + enabled INTEGER NOT NULL DEFAULT TRUE 12 13 ); 13 14 14 15 -- service_status stores historical status checks.
+1
models/models.go
··· 15 15 Name string `json:"name"` 16 16 URL string `json:"url"` 17 17 Headers map[string]string `json:"headers,omitempty"` 18 + Enabled bool `json:"enabled"` 18 19 } 19 20 20 21 // Status repesents a single service status being written
+41 -38
services/monitor.go
··· 104 104 continue 105 105 } 106 106 107 - statuses := make([]models.Status, len(services)) 107 + var statuses []models.Status 108 108 mu := sync.RWMutex{} 109 109 110 110 var wg sync.WaitGroup 111 - for i, svc := range services { 112 - wg.Go(func() { 113 - client := http.Client{ 114 - Timeout: 2 * time.Second, 115 - } 116 - req, err := http.NewRequest(http.MethodGet, svc.URL, nil) 117 - if err != nil { 118 - s.logger.Error("error creating new request", 119 - slog.String("url", svc.URL), 120 - slog.Any("error", err)) 121 - return 122 - } 123 - if svc.Headers != nil { 124 - for k, v := range svc.Headers { 125 - req.Header.Add(k, v) 111 + for _, svc := range services { 112 + if svc.Enabled { 113 + s.logger.Info("service enabled, getting status", slog.String("name", svc.Name), slog.Bool("enabled", svc.Enabled)) 114 + wg.Go(func() { 115 + client := http.Client{ 116 + Timeout: 2 * time.Second, 117 + } 118 + req, err := http.NewRequest(http.MethodGet, svc.URL, nil) 119 + if err != nil { 120 + s.logger.Error("error creating new request", 121 + slog.String("url", svc.URL), 122 + slog.Any("error", err)) 123 + return 124 + } 125 + if svc.Headers != nil { 126 + for k, v := range svc.Headers { 127 + req.Header.Add(k, v) 128 + } 129 + } 130 + var status models.Status 131 + start := time.Now() 132 + resp, err := client.Do(req) 133 + if err != nil { 134 + s.logger.Error("error getting URL", 135 + slog.String("url", svc.URL), 136 + slog.Any("error", err)) 137 + // Server error response OK for now; just need 138 + // to indicate a problem. 139 + status.HTTPStatus = http.StatusServiceUnavailable 140 + } 141 + status.ServiceID = svc.ID 142 + status.Duration = time.Since(start) 143 + status.Timestamp = start 144 + if resp != nil { 145 + status.HTTPStatus = resp.StatusCode 126 146 } 127 - } 128 - var status models.Status 129 - start := time.Now() 130 - resp, err := client.Do(req) 131 - if err != nil { 132 - s.logger.Error("error getting URL", 133 - slog.String("url", svc.URL), 134 - slog.Any("error", err)) 135 - // Server error response OK for now; just need 136 - // to indicate a problem. 137 - status.HTTPStatus = http.StatusServiceUnavailable 138 - } 139 - status.ServiceID = svc.ID 140 - status.Duration = time.Since(start) 141 - status.Timestamp = start 142 - if resp != nil { 143 - status.HTTPStatus = resp.StatusCode 144 - } 145 147 146 - mu.Lock() 147 - statuses[i] = status 148 - mu.Unlock() 149 - }) 148 + mu.Lock() 149 + statuses = append(statuses, status) 150 + mu.Unlock() 151 + }) 152 + } 150 153 } 151 154 wg.Wait() 152 155