Browse Source

refactor(storage): return errors from count functions used by metrics

Return errors instead of zero values or nil from CountUsers,
CountAllFeeds, CountAllFeedsWithErrors, and CountAllEntries so the
metric collector can log failures and preserve previous gauge values.
Frédéric Guillot 2 weeks ago
parent
commit
76452fab99
4 changed files with 35 additions and 20 deletions
  1. 23 8
      internal/metric/metric.go
  2. 3 3
      internal/storage/entry.go
  3. 6 6
      internal/storage/feed.go
  4. 3 3
      internal/storage/user.go

+ 23 - 8
internal/metric/metric.go

@@ -182,17 +182,32 @@ func (c *collector) GatherStorageMetrics(ctx context.Context) {
 		}
 		}
 		slog.Debug("Collecting metrics from the database")
 		slog.Debug("Collecting metrics from the database")
 
 
-		usersGauge.Set(float64(c.store.CountUsers()))
-		brokenFeedsGauge.Set(float64(c.store.CountAllFeedsWithErrors()))
+		if usersCount, err := c.store.CountUsers(); err != nil {
+			slog.Warn("Unable to collect users metric", slog.Any("error", err))
+		} else {
+			usersGauge.Set(float64(usersCount))
+		}
+
+		if brokenFeedsCount, err := c.store.CountAllFeedsWithErrors(); err != nil {
+			slog.Warn("Unable to collect broken feeds metric", slog.Any("error", err))
+		} else {
+			brokenFeedsGauge.Set(float64(brokenFeedsCount))
+		}
 
 
-		feedsCount := c.store.CountAllFeeds()
-		for status, count := range feedsCount {
-			feedsGauge.WithLabelValues(status).Set(float64(count))
+		if feedsCount, err := c.store.CountAllFeeds(); err != nil {
+			slog.Warn("Unable to collect feeds metric", slog.Any("error", err))
+		} else {
+			for status, count := range feedsCount {
+				feedsGauge.WithLabelValues(status).Set(float64(count))
+			}
 		}
 		}
 
 
-		entriesCount := c.store.CountAllEntries()
-		for status, count := range entriesCount {
-			entriesGauge.WithLabelValues(status).Set(float64(count))
+		if entriesCount, err := c.store.CountAllEntries(); err != nil {
+			slog.Warn("Unable to collect entries metric", slog.Any("error", err))
+		} else {
+			for status, count := range entriesCount {
+				entriesGauge.WithLabelValues(status).Set(float64(count))
+			}
 		}
 		}
 
 
 		dbStats := c.store.DBStats()
 		dbStats := c.store.DBStats()

+ 3 - 3
internal/storage/entry.go

@@ -17,10 +17,10 @@ import (
 )
 )
 
 
 // CountAllEntries returns the number of entries for each status in the database.
 // CountAllEntries returns the number of entries for each status in the database.
-func (s *Storage) CountAllEntries() map[string]int64 {
+func (s *Storage) CountAllEntries() (map[string]int64, error) {
 	rows, err := s.db.Query(`SELECT status, count(*) FROM entries GROUP BY status`)
 	rows, err := s.db.Query(`SELECT status, count(*) FROM entries GROUP BY status`)
 	if err != nil {
 	if err != nil {
-		return nil
+		return nil, fmt.Errorf("storage: unable to count entries: %w", err)
 	}
 	}
 	defer rows.Close()
 	defer rows.Close()
 
 
@@ -41,7 +41,7 @@ func (s *Storage) CountAllEntries() map[string]int64 {
 	}
 	}
 
 
 	results["total"] = results[model.EntryStatusUnread] + results[model.EntryStatusRead] + results[model.EntryStatusRemoved]
 	results["total"] = results[model.EntryStatusUnread] + results[model.EntryStatusRead] + results[model.EntryStatusRemoved]
-	return results
+	return results, nil
 }
 }
 
 
 // CountUnreadEntries returns the number of unread entries.
 // CountUnreadEntries returns the number of unread entries.

+ 6 - 6
internal/storage/feed.go

@@ -77,10 +77,10 @@ func (s *Storage) AnotherFeedURLExists(userID, feedID int64, feedURL string) boo
 }
 }
 
 
 // CountAllFeeds returns the number of feeds in the database.
 // CountAllFeeds returns the number of feeds in the database.
-func (s *Storage) CountAllFeeds() map[string]int64 {
+func (s *Storage) CountAllFeeds() (map[string]int64, error) {
 	rows, err := s.db.Query(`SELECT disabled, count(*) FROM feeds GROUP BY disabled`)
 	rows, err := s.db.Query(`SELECT disabled, count(*) FROM feeds GROUP BY disabled`)
 	if err != nil {
 	if err != nil {
-		return nil
+		return nil, fmt.Errorf("storage: unable to count feeds: %w", err)
 	}
 	}
 	defer rows.Close()
 	defer rows.Close()
 
 
@@ -106,7 +106,7 @@ func (s *Storage) CountAllFeeds() map[string]int64 {
 	}
 	}
 
 
 	results["total"] = results["disabled"] + results["enabled"]
 	results["total"] = results["disabled"] + results["enabled"]
-	return results
+	return results, nil
 }
 }
 
 
 // CountUserFeedsWithErrors returns the number of feeds with parsing errors that belong to the given user.
 // CountUserFeedsWithErrors returns the number of feeds with parsing errors that belong to the given user.
@@ -126,7 +126,7 @@ func (s *Storage) CountUserFeedsWithErrors(userID int64) int {
 }
 }
 
 
 // CountAllFeedsWithErrors returns the number of feeds with parsing errors.
 // CountAllFeedsWithErrors returns the number of feeds with parsing errors.
-func (s *Storage) CountAllFeedsWithErrors() int {
+func (s *Storage) CountAllFeedsWithErrors() (int, error) {
 	pollingParsingErrorLimit := config.Opts.PollingParsingErrorLimit()
 	pollingParsingErrorLimit := config.Opts.PollingParsingErrorLimit()
 	if pollingParsingErrorLimit <= 0 {
 	if pollingParsingErrorLimit <= 0 {
 		pollingParsingErrorLimit = 1
 		pollingParsingErrorLimit = 1
@@ -135,10 +135,10 @@ func (s *Storage) CountAllFeedsWithErrors() int {
 	var result int
 	var result int
 	err := s.db.QueryRow(query, pollingParsingErrorLimit).Scan(&result)
 	err := s.db.QueryRow(query, pollingParsingErrorLimit).Scan(&result)
 	if err != nil {
 	if err != nil {
-		return 0
+		return 0, fmt.Errorf("storage: unable to count feeds with errors: %w", err)
 	}
 	}
 
 
-	return result
+	return result, nil
 }
 }
 
 
 // Feeds returns all feeds that belongs to the given user.
 // Feeds returns all feeds that belongs to the given user.

+ 3 - 3
internal/storage/user.go

@@ -18,14 +18,14 @@ import (
 )
 )
 
 
 // CountUsers returns the total number of users.
 // CountUsers returns the total number of users.
-func (s *Storage) CountUsers() int {
+func (s *Storage) CountUsers() (int, error) {
 	var result int
 	var result int
 	err := s.db.QueryRow(`SELECT count(*) FROM users`).Scan(&result)
 	err := s.db.QueryRow(`SELECT count(*) FROM users`).Scan(&result)
 	if err != nil {
 	if err != nil {
-		return 0
+		return 0, fmt.Errorf("storage: unable to count users: %w", err)
 	}
 	}
 
 
-	return result
+	return result, nil
 }
 }
 
 
 // SetLastLogin updates the last login date of a user.
 // SetLastLogin updates the last login date of a user.