chore: metrics performance improvements

This commit is contained in:
Ferdinand Mütsch 2022-03-19 10:30:32 +01:00
parent ec70d024fa
commit bbc85de34b
9 changed files with 751 additions and 723 deletions

File diff suppressed because it is too large Load Diff

View File

@ -20,8 +20,8 @@ func (m *HeartbeatServiceMock) InsertBatch(heartbeats []*models.Heartbeat) error
return args.Error(0) return args.Error(0)
} }
func (m *HeartbeatServiceMock) Count() (int64, error) { func (m *HeartbeatServiceMock) Count(a bool) (int64, error) {
args := m.Called() args := m.Called(a)
return int64(args.Int(0)), args.Error(1) return int64(args.Int(0)), args.Error(1)
} }

View File

@ -1,6 +1,7 @@
package repositories package repositories
import ( import (
conf "github.com/muety/wakapi/config"
"github.com/muety/wakapi/models" "github.com/muety/wakapi/models"
"gorm.io/gorm" "gorm.io/gorm"
"gorm.io/gorm/clause" "gorm.io/gorm/clause"
@ -8,11 +9,12 @@ import (
) )
type HeartbeatRepository struct { type HeartbeatRepository struct {
db *gorm.DB db *gorm.DB
config *conf.Config
} }
func NewHeartbeatRepository(db *gorm.DB) *HeartbeatRepository { func NewHeartbeatRepository(db *gorm.DB) *HeartbeatRepository {
return &HeartbeatRepository{db: db} return &HeartbeatRepository{config: conf.Get(), db: db}
} }
// Use with caution!! // Use with caution!!
@ -116,12 +118,19 @@ func (r *HeartbeatRepository) GetLastByUsers() ([]*models.TimeByUser, error) {
return result, nil return result, nil
} }
func (r *HeartbeatRepository) Count() (int64, error) { func (r *HeartbeatRepository) Count(approximate bool) (count int64, err error) {
var count int64 if r.config.Db.IsMySQL() && approximate {
if err := r.db. err = r.db.Table("information_schema.tables").
Model(&models.Heartbeat{}). Select("table_rows").
Count(&count).Error; err != nil { Where("table_schema = ?", r.config.Db.Name).
return 0, err Where("table_name = 'heartbeats'").
Scan(&count).Error
}
if count == 0 {
err = r.db.
Model(&models.Heartbeat{}).
Count(&count).Error
} }
return count, nil return count, nil
} }
@ -145,6 +154,10 @@ func (r *HeartbeatRepository) CountByUsers(users []*models.User) ([]*models.Coun
userIds[i] = u.ID userIds[i] = u.ID
} }
if len(userIds) == 0 {
return counts, nil
}
if err := r.db. if err := r.db.
Model(&models.Heartbeat{}). Model(&models.Heartbeat{}).
Select("user_id as user, count(id) as count"). Select("user_id as user, count(id) as count").
@ -153,6 +166,7 @@ func (r *HeartbeatRepository) CountByUsers(users []*models.User) ([]*models.Coun
Find(&counts).Error; err != nil { Find(&counts).Error; err != nil {
return counts, err return counts, err
} }
return counts, nil return counts, nil
} }

View File

@ -25,7 +25,7 @@ type IHeartbeatRepository interface {
GetLastByUsers() ([]*models.TimeByUser, error) GetLastByUsers() ([]*models.TimeByUser, error)
GetLatestByUser(*models.User) (*models.Heartbeat, error) GetLatestByUser(*models.User) (*models.Heartbeat, error)
GetLatestByOriginAndUser(string, *models.User) (*models.Heartbeat, error) GetLatestByOriginAndUser(string, *models.User) (*models.Heartbeat, error)
Count() (int64, error) Count(bool) (int64, error)
CountByUser(*models.User) (int64, error) CountByUser(*models.User) (int64, error)
CountByUsers([]*models.User) ([]*models.CountByUser, error) CountByUsers([]*models.User) ([]*models.CountByUser, error)
GetEntitySetByUser(uint8, *models.User) ([]string, error) GetEntitySetByUser(uint8, *models.User) ([]string, error)

View File

@ -98,10 +98,9 @@ func (r *UserRepository) GetByLoggedInAfter(t time.Time) ([]*models.User, error)
// Returns a list of user ids, whose last heartbeat is not older than t // Returns a list of user ids, whose last heartbeat is not older than t
// NOTE: Only ID field will be populated // NOTE: Only ID field will be populated
func (r *UserRepository) GetByLastActiveAfter(t time.Time) ([]*models.User, error) { func (r *UserRepository) GetByLastActiveAfter(t time.Time) ([]*models.User, error) {
subQuery1 := r.db.Model(&models.User{}). subQuery1 := r.db.Model(&models.Heartbeat{}).
Select("users.id as user, max(time) as time"). Select("user_id as user, max(time) as time").
Joins("left join heartbeats on users.id = heartbeats.user_id"). Group("user_id")
Group("user")
var userIds []string var userIds []string
if err := r.db. if err := r.db.

View File

@ -273,7 +273,7 @@ func (h *MetricsHandler) getAdminMetrics(user *models.User) (*mm.Metrics, error)
} }
totalUsers, _ := h.userSrvc.Count() totalUsers, _ := h.userSrvc.Count()
totalHeartbeats, _ := h.heartbeatSrvc.Count() totalHeartbeats, _ := h.heartbeatSrvc.Count(true)
activeUsers, err := h.userSrvc.GetActive(false) activeUsers, err := h.userSrvc.GetActive(false)
if err != nil { if err != nil {

View File

@ -73,12 +73,12 @@ func (srv *HeartbeatService) InsertBatch(heartbeats []*models.Heartbeat) error {
return err return err
} }
func (srv *HeartbeatService) Count() (int64, error) { func (srv *HeartbeatService) Count(approximate bool) (int64, error) {
result, ok := srv.cache.Get(srv.countTotalCacheKey()) result, ok := srv.cache.Get(srv.countTotalCacheKey())
if ok { if ok {
return result.(int64), nil return result.(int64), nil
} }
count, err := srv.repository.Count() count, err := srv.repository.Count(approximate)
if err == nil { if err == nil {
srv.cache.Set(srv.countTotalCacheKey(), count, srv.countCacheTtl()) srv.cache.Set(srv.countTotalCacheKey(), count, srv.countCacheTtl())
} }

View File

@ -29,7 +29,7 @@ type IAliasService interface {
type IHeartbeatService interface { type IHeartbeatService interface {
Insert(*models.Heartbeat) error Insert(*models.Heartbeat) error
InsertBatch([]*models.Heartbeat) error InsertBatch([]*models.Heartbeat) error
Count() (int64, error) Count(bool) (int64, error)
CountByUser(*models.User) (int64, error) CountByUser(*models.User) (int64, error)
CountByUsers([]*models.User) ([]*models.CountByUser, error) CountByUsers([]*models.User) ([]*models.CountByUser, error)
GetAllWithin(time.Time, time.Time, *models.User) ([]*models.Heartbeat, error) GetAllWithin(time.Time, time.Time, *models.User) ([]*models.Heartbeat, error)

View File

@ -1 +1 @@
2.3.0 2.3.1