feat: add last active time per user

This commit is contained in:
Sam 2023-05-02 02:54:08 +02:00
parent 90c7dcf891
commit cf95e69349
Signed by: sam
GPG key ID: B4EF20DDE721CAA1
8 changed files with 85 additions and 234 deletions

View file

@ -6,8 +6,10 @@ import (
"codeberg.org/u1f320/pronouns.cc/backend/log"
"emperror.dev/errors"
"github.com/jackc/pgx/v5/pgconn"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promauto"
"github.com/rs/xid"
)
func (db *DB) initMetrics() (err error) {
@ -39,6 +41,20 @@ func (db *DB) initMetrics() (err error) {
return errors.Wrap(err, "registering member count gauge")
}
err = prometheus.Register(prometheus.NewGaugeFunc(prometheus.GaugeOpts{
Name: "pronouns_users_active",
Help: "The number of users active in the past 30 days",
}, func() float64 {
count, err := db.ActiveUsers(context.Background())
if err != nil {
log.Errorf("getting active user count for metrics: %v", err)
}
return float64(count)
}))
if err != nil {
return errors.Wrap(err, "registering active user count gauge")
}
err = prometheus.Register(prometheus.NewGaugeFunc(prometheus.GaugeOpts{
Name: "pronouns_database_latency",
Help: "The latency to the database in nanoseconds",
@ -51,6 +67,9 @@ func (db *DB) initMetrics() (err error) {
}
return float64(time.Since(start))
}))
if err != nil {
return errors.Wrap(err, "registering database latency gauge")
}
db.TotalRequests = promauto.NewCounter(prometheus.CounterOpts{
Name: "pronouns_api_requests_total",
@ -75,3 +94,32 @@ func (db *DB) TotalMemberCount(ctx context.Context) (numMembers int64, err error
}
return numMembers, nil
}
const activeTime = 30 * 24 * time.Hour
func (db *DB) ActiveUsers(ctx context.Context) (numUsers int64, err error) {
t := time.Now().Add(-activeTime)
err = db.QueryRow(ctx, "SELECT COUNT(*) FROM users WHERE deleted_at IS NULL AND last_active > $1", t).Scan(&numUsers)
if err != nil {
return 0, errors.Wrap(err, "querying active user count")
}
return numUsers, nil
}
type connOrTx interface {
Exec(ctx context.Context, sql string, arguments ...any) (commandTag pgconn.CommandTag, err error)
}
// UpdateActiveTime is called on create and update endpoints (PATCH /users/@me, POST/PATCH/DELETE /members)
func (db *DB) UpdateActiveTime(ctx context.Context, tx connOrTx, userID xid.ID) (err error) {
sql, args, err := sq.Update("users").Set("last_active", time.Now().UTC()).Where("id = ?", userID).ToSql()
if err != nil {
return errors.Wrap(err, "building sql")
}
_, err = tx.Exec(ctx, sql, args...)
if err != nil {
return errors.Wrap(err, "executing query")
}
return nil
}

View file

@ -24,6 +24,7 @@ type User struct {
DisplayName *string
Bio *string
MemberTitle *string
LastActive time.Time
Avatar *string
Links []string