Chore: Add context to star and stats (#39591)

* Add context to star and stats

* Use WithTransactionalDbSession

* Add additional ctx

* Remove convey

* Fix star handler name

* Use WithDbSession, use DispatchCtx

* Remove xorm from star
This commit is contained in:
idafurjes 2021-09-28 17:54:45 +02:00 committed by GitHub
parent 580cdc46fc
commit b255c1b992
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 71 additions and 67 deletions

View File

@ -22,7 +22,7 @@ func (hs *HTTPServer) AdminGetSettings(c *models.ReqContext) response.Response {
func AdminGetStats(c *models.ReqContext) response.Response {
statsQuery := models.GetAdminStatsQuery{}
if err := bus.Dispatch(&statsQuery); err != nil {
if err := bus.DispatchCtx(c.Req.Context(), &statsQuery); err != nil {
return response.Error(500, "Failed to get admin stats from database", err)
}

View File

@ -49,7 +49,7 @@ func ProvideService(cfg *setting.Cfg, bus bus.Bus, sqlStore *sqlstore.SQLStore,
}
func (uss *UsageStats) Run(ctx context.Context) error {
uss.updateTotalStats()
uss.updateTotalStats(ctx)
// try to load last sent time from kv store
lastSent := time.Now()
@ -97,7 +97,7 @@ func (uss *UsageStats) Run(ctx context.Context) error {
callback()
}
case <-updateStatsTicker.C:
uss.updateTotalStats()
uss.updateTotalStats(ctx)
case <-ctx.Done():
return ctx.Err()
}

View File

@ -38,7 +38,7 @@ func (uss *UsageStats) GetUsageReport(ctx context.Context) (usagestats.Report, e
}
statsQuery := models.GetSystemStatsQuery{}
if err := uss.Bus.Dispatch(&statsQuery); err != nil {
if err := uss.Bus.DispatchCtx(ctx, &statsQuery); err != nil {
uss.log.Error("Failed to get system stats", "error", err)
return report, err
}
@ -110,7 +110,7 @@ func (uss *UsageStats) GetUsageReport(ctx context.Context) (usagestats.Report, e
metrics["stats.avg_auth_token_per_user.count"] = avgAuthTokensPerUser
dsStats := models.GetDataSourceStatsQuery{}
if err := uss.Bus.Dispatch(&dsStats); err != nil {
if err := uss.Bus.DispatchCtx(ctx, &dsStats); err != nil {
uss.log.Error("Failed to get datasource stats", "error", err)
return report, err
}
@ -129,7 +129,7 @@ func (uss *UsageStats) GetUsageReport(ctx context.Context) (usagestats.Report, e
metrics["stats.ds.other.count"] = dsOtherCount
esDataSourcesQuery := models.GetDataSourcesByTypeQuery{Type: models.DS_ES}
if err := uss.Bus.Dispatch(&esDataSourcesQuery); err != nil {
if err := uss.Bus.DispatchCtx(ctx, &esDataSourcesQuery); err != nil {
uss.log.Error("Failed to get elasticsearch json data", "error", err)
return report, err
}
@ -152,7 +152,7 @@ func (uss *UsageStats) GetUsageReport(ctx context.Context) (usagestats.Report, e
// fetch datasource access stats
dsAccessStats := models.GetDataSourceAccessStatsQuery{}
if err := uss.Bus.Dispatch(&dsAccessStats); err != nil {
if err := uss.Bus.DispatchCtx(ctx, &dsAccessStats); err != nil {
uss.log.Error("Failed to get datasource access stats", "error", err)
return report, err
}
@ -287,13 +287,13 @@ var sendUsageStats = func(uss *UsageStats, data *bytes.Buffer) {
}()
}
func (uss *UsageStats) updateTotalStats() {
func (uss *UsageStats) updateTotalStats(ctx context.Context) {
if !uss.Cfg.MetricsEndpointEnabled || uss.Cfg.MetricsEndpointDisableTotalStats {
return
}
statsQuery := models.GetSystemStatsQuery{}
if err := uss.Bus.Dispatch(&statsQuery); err != nil {
if err := uss.Bus.DispatchCtx(ctx, &statsQuery); err != nil {
uss.log.Error("Failed to get system stats", "error", err)
return
}
@ -317,7 +317,7 @@ func (uss *UsageStats) updateTotalStats() {
metrics.StatsTotalLibraryVariables.Set(float64(statsQuery.Result.LibraryVariables))
dsStats := models.GetDataSourceStatsQuery{}
if err := uss.Bus.Dispatch(&dsStats); err != nil {
if err := uss.Bus.DispatchCtx(ctx, &dsStats); err != nil {
uss.log.Error("Failed to get datasource stats", "error", err)
return
}

View File

@ -411,7 +411,7 @@ func TestMetrics(t *testing.T) {
t.Run("When metrics is disabled and total stats is enabled, stats should not be updated", func(t *testing.T) {
uss.Cfg.MetricsEndpointEnabled = false
uss.Cfg.MetricsEndpointDisableTotalStats = false
uss.updateTotalStats()
uss.updateTotalStats(context.Background())
assert.False(t, getSystemStatsWasCalled)
})
@ -420,7 +420,7 @@ func TestMetrics(t *testing.T) {
uss.Cfg.MetricsEndpointEnabled = true
uss.Cfg.MetricsEndpointDisableTotalStats = true
uss.updateTotalStats()
uss.updateTotalStats(context.Background())
assert.False(t, getSystemStatsWasCalled)
})
@ -429,7 +429,7 @@ func TestMetrics(t *testing.T) {
uss.Cfg.MetricsEndpointEnabled = false
uss.Cfg.MetricsEndpointDisableTotalStats = true
uss.updateTotalStats()
uss.updateTotalStats(context.Background())
assert.False(t, getSystemStatsWasCalled)
})
@ -438,7 +438,7 @@ func TestMetrics(t *testing.T) {
uss.Cfg.MetricsEndpointEnabled = true
uss.Cfg.MetricsEndpointDisableTotalStats = false
uss.updateTotalStats()
uss.updateTotalStats(context.Background())
assert.True(t, getSystemStatsWasCalled)
})

View File

@ -386,13 +386,13 @@ func TestDashboardDataAccess(t *testing.T) {
Convey("Given two dashboards, one is starred dashboard by user 10, other starred by user 1", func() {
starredDash := insertTestDashboard(t, sqlStore, "starred dash", 1, 0, false)
err := StarDashboard(&models.StarDashboardCommand{
err := sqlStore.StarDashboard(context.Background(), &models.StarDashboardCommand{
DashboardId: starredDash.Id,
UserId: 10,
})
So(err, ShouldBeNil)
err = StarDashboard(&models.StarDashboardCommand{
err = sqlStore.StarDashboard(context.Background(), &models.StarDashboardCommand{
DashboardId: savedDash.Id,
UserId: 1,
})

View File

@ -116,6 +116,7 @@ func newSQLStore(cfg *setting.Cfg, cacheService *localcache.CacheService, bus bu
ss.addDashboardACLQueryAndCommandHandlers()
ss.addQuotaQueryAndCommandHandlers()
ss.addOrgUsersQueryAndCommandHandlers()
ss.addStarQueryAndCommandHandlers()
// if err := ss.Reset(); err != nil {
// return nil, err

View File

@ -7,17 +7,17 @@ import (
"github.com/grafana/grafana/pkg/models"
)
func init() {
bus.AddHandler("sql", StarDashboard)
bus.AddHandler("sql", UnstarDashboard)
bus.AddHandler("sql", GetUserStars)
bus.AddHandlerCtx("sql", IsStarredByUserCtx)
func (ss *SQLStore) addStarQueryAndCommandHandlers() {
bus.AddHandlerCtx("sql", ss.StarDashboard)
bus.AddHandlerCtx("sql", ss.UnstarDashboard)
bus.AddHandlerCtx("sql", ss.GetUserStars)
bus.AddHandlerCtx("sql", ss.IsStarredByUserCtx)
}
func IsStarredByUserCtx(ctx context.Context, query *models.IsStarredByUserQuery) error {
return withDbSession(ctx, x, func(dbSession *DBSession) error {
func (ss *SQLStore) IsStarredByUserCtx(ctx context.Context, query *models.IsStarredByUserQuery) error {
return ss.WithDbSession(ctx, func(sess *DBSession) error {
rawSQL := "SELECT 1 from star where user_id=? and dashboard_id=?"
results, err := dbSession.Query(rawSQL, query.UserId, query.DashboardId)
results, err := sess.Query(rawSQL, query.UserId, query.DashboardId)
if err != nil {
return err
@ -33,12 +33,12 @@ func IsStarredByUserCtx(ctx context.Context, query *models.IsStarredByUserQuery)
})
}
func StarDashboard(cmd *models.StarDashboardCommand) error {
func (ss *SQLStore) StarDashboard(ctx context.Context, cmd *models.StarDashboardCommand) error {
if cmd.DashboardId == 0 || cmd.UserId == 0 {
return models.ErrCommandValidationFailed
}
return inTransaction(func(sess *DBSession) error {
return ss.WithTransactionalDbSession(ctx, func(sess *DBSession) error {
entity := models.Star{
UserId: cmd.UserId,
DashboardId: cmd.DashboardId,
@ -49,26 +49,28 @@ func StarDashboard(cmd *models.StarDashboardCommand) error {
})
}
func UnstarDashboard(cmd *models.UnstarDashboardCommand) error {
func (ss *SQLStore) UnstarDashboard(ctx context.Context, cmd *models.UnstarDashboardCommand) error {
if cmd.DashboardId == 0 || cmd.UserId == 0 {
return models.ErrCommandValidationFailed
}
return inTransaction(func(sess *DBSession) error {
return ss.WithTransactionalDbSession(ctx, func(sess *DBSession) error {
var rawSQL = "DELETE FROM star WHERE user_id=? and dashboard_id=?"
_, err := sess.Exec(rawSQL, cmd.UserId, cmd.DashboardId)
return err
})
}
func GetUserStars(query *models.GetUserStarsQuery) error {
var stars = make([]models.Star, 0)
err := x.Where("user_id=?", query.UserId).Find(&stars)
func (ss *SQLStore) GetUserStars(ctx context.Context, query *models.GetUserStarsQuery) error {
return ss.WithDbSession(ctx, func(dbSession *DBSession) error {
var stars = make([]models.Star, 0)
err := dbSession.Where("user_id=?", query.UserId).Find(&stars)
query.Result = make(map[int64]bool)
for _, star := range stars {
query.Result[star.DashboardId] = true
}
query.Result = make(map[int64]bool)
for _, star := range stars {
query.Result[star.DashboardId] = true
}
return err
return err
})
}

View File

@ -8,36 +8,36 @@ import (
"testing"
"github.com/grafana/grafana/pkg/models"
. "github.com/smartystreets/goconvey/convey"
"github.com/stretchr/testify/require"
)
func TestUserStarsDataAccess(t *testing.T) {
Convey("Testing User Stars Data Access", t, func() {
InitTestDB(t)
t.Run("Testing User Stars Data Access", func(t *testing.T) {
sqlStore := InitTestDB(t)
Convey("Given saved star", func() {
t.Run("Given saved star", func(t *testing.T) {
cmd := models.StarDashboardCommand{
DashboardId: 10,
UserId: 12,
}
err := StarDashboard(&cmd)
So(err, ShouldBeNil)
err := sqlStore.StarDashboard(context.Background(), &cmd)
require.NoError(t, err)
Convey("IsStarredByUser should return true when starred", func() {
t.Run("IsStarredByUser should return true when starred", func(t *testing.T) {
query := models.IsStarredByUserQuery{UserId: 12, DashboardId: 10}
err := IsStarredByUserCtx(context.Background(), &query)
So(err, ShouldBeNil)
err := sqlStore.IsStarredByUserCtx(context.Background(), &query)
require.NoError(t, err)
So(query.Result, ShouldBeTrue)
require.True(t, query.Result)
})
Convey("IsStarredByUser should return false when not starred", func() {
t.Run("IsStarredByUser should return false when not starred", func(t *testing.T) {
query := models.IsStarredByUserQuery{UserId: 12, DashboardId: 12}
err := IsStarredByUserCtx(context.Background(), &query)
So(err, ShouldBeNil)
err := sqlStore.IsStarredByUserCtx(context.Background(), &query)
require.NoError(t, err)
So(query.Result, ShouldBeFalse)
require.False(t, query.Result)
})
})
})

View File

@ -10,10 +10,10 @@ import (
)
func init() {
bus.AddHandler("sql", GetSystemStats)
bus.AddHandler("sql", GetDataSourceStats)
bus.AddHandler("sql", GetDataSourceAccessStats)
bus.AddHandler("sql", GetAdminStats)
bus.AddHandlerCtx("sql", GetSystemStats)
bus.AddHandlerCtx("sql", GetDataSourceStats)
bus.AddHandlerCtx("sql", GetDataSourceAccessStats)
bus.AddHandlerCtx("sql", GetAdminStats)
bus.AddHandlerCtx("sql", GetAlertNotifiersUsageStats)
bus.AddHandlerCtx("sql", GetSystemUserCountStats)
}
@ -28,21 +28,21 @@ func GetAlertNotifiersUsageStats(ctx context.Context, query *models.GetAlertNoti
return err
}
func GetDataSourceStats(query *models.GetDataSourceStatsQuery) error {
func GetDataSourceStats(ctx context.Context, query *models.GetDataSourceStatsQuery) error {
var rawSQL = `SELECT COUNT(*) AS count, type FROM ` + dialect.Quote("data_source") + ` GROUP BY type`
query.Result = make([]*models.DataSourceStats, 0)
err := x.SQL(rawSQL).Find(&query.Result)
return err
}
func GetDataSourceAccessStats(query *models.GetDataSourceAccessStatsQuery) error {
func GetDataSourceAccessStats(ctx context.Context, query *models.GetDataSourceAccessStatsQuery) error {
var rawSQL = `SELECT COUNT(*) AS count, type, access FROM ` + dialect.Quote("data_source") + ` GROUP BY type, access`
query.Result = make([]*models.DataSourceAccessStats, 0)
err := x.SQL(rawSQL).Find(&query.Result)
return err
}
func GetSystemStats(query *models.GetSystemStatsQuery) error {
func GetSystemStats(ctx context.Context, query *models.GetSystemStatsQuery) error {
sb := &SQLBuilder{}
sb.Write("SELECT ")
sb.Write(`(SELECT COUNT(*) FROM ` + dialect.Quote("user") + `) AS users,`)
@ -92,7 +92,7 @@ func GetSystemStats(query *models.GetSystemStatsQuery) error {
sb.Write(`(SELECT COUNT(id) FROM `+dialect.Quote("library_element")+` WHERE kind = ?) AS library_panels,`, models.PanelElement)
sb.Write(`(SELECT COUNT(id) FROM `+dialect.Quote("library_element")+` WHERE kind = ?) AS library_variables,`, models.VariableElement)
sb.Write(roleCounterSQL())
sb.Write(roleCounterSQL(ctx))
var stats models.SystemStats
_, err := x.SQL(sb.GetSQLString(), sb.params...).Get(&stats)
@ -105,9 +105,9 @@ func GetSystemStats(query *models.GetSystemStatsQuery) error {
return nil
}
func roleCounterSQL() string {
func roleCounterSQL(ctx context.Context) string {
const roleCounterTimeout = 20 * time.Second
ctx, cancel := context.WithTimeout(context.Background(), roleCounterTimeout)
ctx, cancel := context.WithTimeout(ctx, roleCounterTimeout)
defer cancel()
_ = updateUserRoleCountsIfNecessary(ctx, false)
sqlQuery :=
@ -136,7 +136,7 @@ func viewersPermissionsCounterSQL(statName string, isFolder bool, permission mod
) AS ` + statName + `, `
}
func GetAdminStats(query *models.GetAdminStatsQuery) error {
func GetAdminStats(ctx context.Context, query *models.GetAdminStatsQuery) error {
activeEndDate := time.Now().Add(-activeUserTimeLimit)
dailyActiveEndDate := time.Now().Add(-dailyActiveUserTimeLimit)
@ -185,7 +185,7 @@ func GetAdminStats(query *models.GetAdminStatsQuery) error {
SELECT COUNT(*)
FROM ` + dialect.Quote("user") + ` WHERE last_seen_at > ?
) AS daily_active_users,
` + roleCounterSQL() + `,
` + roleCounterSQL(ctx) + `,
(
SELECT COUNT(*)
FROM ` + dialect.Quote("user_auth_token") + ` WHERE rotated_at > ?

View File

@ -4,6 +4,7 @@
package sqlstore
import (
"context"
"testing"
"github.com/grafana/grafana/pkg/models"
@ -14,6 +15,6 @@ func TestIntegration_GetAdminStats(t *testing.T) {
InitTestDB(t)
query := models.GetAdminStatsQuery{}
err := GetAdminStats(&query)
err := GetAdminStats(context.Background(), &query)
require.NoError(t, err)
}

View File

@ -19,7 +19,7 @@ func TestStatsDataAccess(t *testing.T) {
t.Run("Get system stats should not results in error", func(t *testing.T) {
query := models.GetSystemStatsQuery{}
err := GetSystemStats(&query)
err := GetSystemStats(context.Background(), &query)
require.NoError(t, err)
assert.Equal(t, int64(3), query.Result.Users)
assert.Equal(t, int64(0), query.Result.Editors)
@ -37,13 +37,13 @@ func TestStatsDataAccess(t *testing.T) {
t.Run("Get datasource stats should not results in error", func(t *testing.T) {
query := models.GetDataSourceStatsQuery{}
err := GetDataSourceStats(&query)
err := GetDataSourceStats(context.Background(), &query)
assert.NoError(t, err)
})
t.Run("Get datasource access stats should not results in error", func(t *testing.T) {
query := models.GetDataSourceAccessStatsQuery{}
err := GetDataSourceAccessStats(&query)
err := GetDataSourceAccessStats(context.Background(), &query)
assert.NoError(t, err)
})
@ -55,7 +55,7 @@ func TestStatsDataAccess(t *testing.T) {
t.Run("Get admin stats should not result in error", func(t *testing.T) {
query := models.GetAdminStatsQuery{}
err := GetAdminStats(&query)
err := GetAdminStats(context.Background(), &query)
assert.NoError(t, err)
})
}