feat(backend): cache user/member counts
This commit is contained in:
		
							parent
							
								
									af1403d0c9
								
							
						
					
					
						commit
						80cf699a73
					
				
					 3 changed files with 47 additions and 26 deletions
				
			
		|  | @ -6,6 +6,7 @@ import ( | |||
| 	"fmt" | ||||
| 	"net/url" | ||||
| 	"os" | ||||
| 	"sync" | ||||
| 
 | ||||
| 	"codeberg.org/pronounscc/pronouns.cc/backend/log" | ||||
| 	"emperror.dev/errors" | ||||
|  | @ -41,6 +42,10 @@ type DB struct { | |||
| 	baseURL     *url.URL | ||||
| 
 | ||||
| 	TotalRequests prometheus.Counter | ||||
| 
 | ||||
| 	activeUsersDay, activeUsersWeek, activeUsersMonth int64 | ||||
| 	usersTotal, membersTotal                          int64 | ||||
| 	countMu                                           sync.RWMutex | ||||
| } | ||||
| 
 | ||||
| func New() (*DB, error) { | ||||
|  |  | |||
|  | @ -21,6 +21,11 @@ func (db *DB) initMetrics() (err error) { | |||
| 		if err != nil { | ||||
| 			log.Errorf("getting user count for metrics: %v", err) | ||||
| 		} | ||||
| 
 | ||||
| 		db.countMu.Lock() | ||||
| 		db.usersTotal = count | ||||
| 		db.countMu.Unlock() | ||||
| 
 | ||||
| 		return float64(count) | ||||
| 	})) | ||||
| 	if err != nil { | ||||
|  | @ -35,6 +40,11 @@ func (db *DB) initMetrics() (err error) { | |||
| 		if err != nil { | ||||
| 			log.Errorf("getting member count for metrics: %v", err) | ||||
| 		} | ||||
| 
 | ||||
| 		db.countMu.Lock() | ||||
| 		db.membersTotal = count | ||||
| 		db.countMu.Unlock() | ||||
| 
 | ||||
| 		return float64(count) | ||||
| 	})) | ||||
| 	if err != nil { | ||||
|  | @ -49,6 +59,11 @@ func (db *DB) initMetrics() (err error) { | |||
| 		if err != nil { | ||||
| 			log.Errorf("getting active user count for metrics: %v", err) | ||||
| 		} | ||||
| 
 | ||||
| 		db.countMu.Lock() | ||||
| 		db.activeUsersMonth = count | ||||
| 		db.countMu.Unlock() | ||||
| 
 | ||||
| 		return float64(count) | ||||
| 	})) | ||||
| 	if err != nil { | ||||
|  | @ -63,6 +78,11 @@ func (db *DB) initMetrics() (err error) { | |||
| 		if err != nil { | ||||
| 			log.Errorf("getting active user count for metrics: %v", err) | ||||
| 		} | ||||
| 
 | ||||
| 		db.countMu.Lock() | ||||
| 		db.activeUsersWeek = count | ||||
| 		db.countMu.Unlock() | ||||
| 
 | ||||
| 		return float64(count) | ||||
| 	})) | ||||
| 	if err != nil { | ||||
|  | @ -77,6 +97,11 @@ func (db *DB) initMetrics() (err error) { | |||
| 		if err != nil { | ||||
| 			log.Errorf("getting active user count for metrics: %v", err) | ||||
| 		} | ||||
| 
 | ||||
| 		db.countMu.Lock() | ||||
| 		db.activeUsersDay = count | ||||
| 		db.countMu.Unlock() | ||||
| 
 | ||||
| 		return float64(count) | ||||
| 	})) | ||||
| 	if err != nil { | ||||
|  | @ -107,6 +132,22 @@ func (db *DB) initMetrics() (err error) { | |||
| 	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) { | ||||
| 	err = db.QueryRow(ctx, "SELECT COUNT(*) FROM users WHERE deleted_at IS NULL").Scan(&numUsers) | ||||
| 	if err != nil { | ||||
|  |  | |||
|  | @ -4,9 +4,7 @@ import ( | |||
| 	"net/http" | ||||
| 	"os" | ||||
| 
 | ||||
| 	"codeberg.org/pronounscc/pronouns.cc/backend/db" | ||||
| 	"codeberg.org/pronounscc/pronouns.cc/backend/server" | ||||
| 	"emperror.dev/errors" | ||||
| 	"github.com/go-chi/chi/v5" | ||||
| 	"github.com/go-chi/render" | ||||
| ) | ||||
|  | @ -39,30 +37,7 @@ type MetaUsers struct { | |||
| func (s *Server) meta(w http.ResponseWriter, r *http.Request) error { | ||||
| 	ctx := r.Context() | ||||
| 
 | ||||
| 	numUsers, err := s.DB.TotalUserCount(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") | ||||
| 	} | ||||
| 	numUsers, numMembers, activeDay, activeWeek, activeMonth := s.DB.Counts(ctx) | ||||
| 
 | ||||
| 	render.JSON(w, r, MetaResponse{ | ||||
| 		GitRepository: server.Repository, | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue