feat(backend): cache user/member counts

This commit is contained in:
Sam 2023-06-25 15:49:19 +02:00
parent af1403d0c9
commit 80cf699a73
No known key found for this signature in database
GPG key ID: B4EF20DDE721CAA1
3 changed files with 47 additions and 26 deletions

View file

@ -6,6 +6,7 @@ import (
"fmt" "fmt"
"net/url" "net/url"
"os" "os"
"sync"
"codeberg.org/pronounscc/pronouns.cc/backend/log" "codeberg.org/pronounscc/pronouns.cc/backend/log"
"emperror.dev/errors" "emperror.dev/errors"
@ -41,6 +42,10 @@ type DB struct {
baseURL *url.URL baseURL *url.URL
TotalRequests prometheus.Counter TotalRequests prometheus.Counter
activeUsersDay, activeUsersWeek, activeUsersMonth int64
usersTotal, membersTotal int64
countMu sync.RWMutex
} }
func New() (*DB, error) { func New() (*DB, error) {

View file

@ -21,6 +21,11 @@ func (db *DB) initMetrics() (err error) {
if err != nil { if err != nil {
log.Errorf("getting user count for metrics: %v", err) log.Errorf("getting user count for metrics: %v", err)
} }
db.countMu.Lock()
db.usersTotal = count
db.countMu.Unlock()
return float64(count) return float64(count)
})) }))
if err != nil { if err != nil {
@ -35,6 +40,11 @@ func (db *DB) initMetrics() (err error) {
if err != nil { if err != nil {
log.Errorf("getting member count for metrics: %v", err) log.Errorf("getting member count for metrics: %v", err)
} }
db.countMu.Lock()
db.membersTotal = count
db.countMu.Unlock()
return float64(count) return float64(count)
})) }))
if err != nil { if err != nil {
@ -49,6 +59,11 @@ func (db *DB) initMetrics() (err error) {
if err != nil { if err != nil {
log.Errorf("getting active user count for metrics: %v", err) log.Errorf("getting active user count for metrics: %v", err)
} }
db.countMu.Lock()
db.activeUsersMonth = count
db.countMu.Unlock()
return float64(count) return float64(count)
})) }))
if err != nil { if err != nil {
@ -63,6 +78,11 @@ func (db *DB) initMetrics() (err error) {
if err != nil { if err != nil {
log.Errorf("getting active user count for metrics: %v", err) log.Errorf("getting active user count for metrics: %v", err)
} }
db.countMu.Lock()
db.activeUsersWeek = count
db.countMu.Unlock()
return float64(count) return float64(count)
})) }))
if err != nil { if err != nil {
@ -77,6 +97,11 @@ func (db *DB) initMetrics() (err error) {
if err != nil { if err != nil {
log.Errorf("getting active user count for metrics: %v", err) log.Errorf("getting active user count for metrics: %v", err)
} }
db.countMu.Lock()
db.activeUsersDay = count
db.countMu.Unlock()
return float64(count) return float64(count)
})) }))
if err != nil { if err != nil {
@ -107,6 +132,22 @@ func (db *DB) initMetrics() (err error) {
return nil return nil
} }
func (db *DB) Counts(ctx context.Context) (numUsers, numMembers, usersDay, usersWeek, usersMonth int64) {
db.countMu.Lock()
if numUsers != 0 {
defer db.countMu.Unlock()
return db.usersTotal, db.membersTotal, db.activeUsersDay, db.activeUsersWeek, db.activeUsersMonth
}
db.countMu.Unlock()
numUsers, _ = db.TotalUserCount(ctx)
numMembers, _ = db.TotalMemberCount(ctx)
usersDay, _ = db.ActiveUsers(ctx, ActiveDay)
usersWeek, _ = db.ActiveUsers(ctx, ActiveWeek)
usersMonth, _ = db.ActiveUsers(ctx, ActiveMonth)
return numUsers, numMembers, usersDay, usersWeek, usersMonth
}
func (db *DB) TotalUserCount(ctx context.Context) (numUsers int64, err error) { func (db *DB) TotalUserCount(ctx context.Context) (numUsers int64, err error) {
err = db.QueryRow(ctx, "SELECT COUNT(*) FROM users WHERE deleted_at IS NULL").Scan(&numUsers) err = db.QueryRow(ctx, "SELECT COUNT(*) FROM users WHERE deleted_at IS NULL").Scan(&numUsers)
if err != nil { if err != nil {

View file

@ -4,9 +4,7 @@ import (
"net/http" "net/http"
"os" "os"
"codeberg.org/pronounscc/pronouns.cc/backend/db"
"codeberg.org/pronounscc/pronouns.cc/backend/server" "codeberg.org/pronounscc/pronouns.cc/backend/server"
"emperror.dev/errors"
"github.com/go-chi/chi/v5" "github.com/go-chi/chi/v5"
"github.com/go-chi/render" "github.com/go-chi/render"
) )
@ -39,30 +37,7 @@ type MetaUsers struct {
func (s *Server) meta(w http.ResponseWriter, r *http.Request) error { func (s *Server) meta(w http.ResponseWriter, r *http.Request) error {
ctx := r.Context() ctx := r.Context()
numUsers, err := s.DB.TotalUserCount(ctx) numUsers, numMembers, activeDay, activeWeek, activeMonth := s.DB.Counts(ctx)
if err != nil {
return errors.Wrap(err, "querying user count")
}
activeMonth, err := s.DB.ActiveUsers(ctx, db.ActiveMonth)
if err != nil {
return errors.Wrap(err, "querying user count")
}
activeWeek, err := s.DB.ActiveUsers(ctx, db.ActiveWeek)
if err != nil {
return errors.Wrap(err, "querying user count")
}
activeDay, err := s.DB.ActiveUsers(ctx, db.ActiveDay)
if err != nil {
return errors.Wrap(err, "querying user count")
}
numMembers, err := s.DB.TotalMemberCount(ctx)
if err != nil {
return errors.Wrap(err, "querying user count")
}
render.JSON(w, r, MetaResponse{ render.JSON(w, r, MetaResponse{
GitRepository: server.Repository, GitRepository: server.Repository,