Migrate from usage of channels to waitgroups on app/analytics.go (#16929)

* Migrate from usage of channels to waitgroups on app/analytics.go

* Grouping error handling to simplify the code

* Using errgroup.Group instead of sync.WaitGroup

* Returning correctly the errors

* Update app/analytics.go

Co-authored-by: Miguel de la Cruz <mgdelacroix@gmail.com>

* Renaming g with g2 for clarity

Co-authored-by: Miguel de la Cruz <mgdelacroix@gmail.com>
Этот коммит содержится в:
Jesús Espino
2021-02-22 14:48:13 +01:00
коммит произвёл GitHub
родитель 2b6c0e9746
Коммит 33534a7fa6

Просмотреть файл

@@ -6,9 +6,10 @@ package app
import (
"net/http"
"golang.org/x/sync/errgroup"
"github.com/mattermost/mattermost-server/v5/mlog"
"github.com/mattermost/mattermost-server/v5/model"
"github.com/mattermost/mattermost-server/v5/store"
)
const (
@@ -43,115 +44,105 @@ func (a *App) GetAnalytics(name string, teamID string) (model.AnalyticsRows, *mo
rows[9] = &model.AnalyticsRow{Name: "monthly_active_users", Value: 0}
rows[10] = &model.AnalyticsRow{Name: "inactive_user_count", Value: 0}
openChan := make(chan store.StoreResult, 1)
privateChan := make(chan store.StoreResult, 1)
go func() {
count, err2 := a.Srv().Store.Channel().AnalyticsTypeCount(teamID, model.CHANNEL_OPEN)
openChan <- store.StoreResult{Data: count, NErr: err2}
close(openChan)
}()
go func() {
count, err2 := a.Srv().Store.Channel().AnalyticsTypeCount(teamID, model.CHANNEL_PRIVATE)
privateChan <- store.StoreResult{Data: count, NErr: err2}
close(privateChan)
}()
var g errgroup.Group
var openChannelsCount int64
g.Go(func() error {
var err error
if openChannelsCount, err = a.Srv().Store.Channel().AnalyticsTypeCount(teamID, model.CHANNEL_OPEN); err != nil {
return model.NewAppError("GetAnalytics", "app.channel.analytics_type_count.app_error", nil, err.Error(), http.StatusInternalServerError)
}
return nil
})
var userChan chan store.StoreResult
var userInactiveChan chan store.StoreResult
var privateChannelsCount int64
g.Go(func() error {
var err error
if privateChannelsCount, err = a.Srv().Store.Channel().AnalyticsTypeCount(teamID, model.CHANNEL_PRIVATE); err != nil {
return model.NewAppError("GetAnalytics", "app.channel.analytics_type_count.app_error", nil, err.Error(), http.StatusInternalServerError)
}
return nil
})
var usersCount int64
var inactiveUsersCount int64
if teamID == "" {
userInactiveChan = make(chan store.StoreResult, 1)
go func() {
count, err2 := a.Srv().Store.User().AnalyticsGetInactiveUsersCount()
userInactiveChan <- store.StoreResult{Data: count, NErr: err2}
close(userInactiveChan)
}()
g.Go(func() error {
var err error
if inactiveUsersCount, err = a.Srv().Store.User().AnalyticsGetInactiveUsersCount(); err != nil {
return model.NewAppError("GetAnalytics", "app.user.analytics_get_inactive_users_count.app_error", nil, err.Error(), http.StatusInternalServerError)
}
return nil
})
} else {
userChan = make(chan store.StoreResult, 1)
go func() {
count, err2 := a.Srv().Store.User().Count(model.UserCountOptions{TeamId: teamID})
userChan <- store.StoreResult{Data: count, NErr: err2}
close(userChan)
}()
g.Go(func() error {
var err error
if usersCount, err = a.Srv().Store.User().Count(model.UserCountOptions{TeamId: teamID}); err != nil {
return model.NewAppError("GetAnalytics", "app.user.get_total_users_count.app_error", nil, err.Error(), http.StatusInternalServerError)
}
return nil
})
}
var postChan chan store.StoreResult
var postsCount int64
if !skipIntensiveQueries {
postChan = make(chan store.StoreResult, 1)
go func() {
count, err2 := a.Srv().Store.Post().AnalyticsPostCount(teamID, false, false)
postChan <- store.StoreResult{Data: count, NErr: err2}
close(postChan)
}()
g.Go(func() error {
var err error
if postsCount, err = a.Srv().Store.Post().AnalyticsPostCount(teamID, false, false); err != nil {
return model.NewAppError("GetAnalytics", "app.post.analytics_posts_count.app_error", nil, err.Error(), http.StatusInternalServerError)
}
return nil
})
}
teamCountChan := make(chan store.StoreResult, 1)
go func() {
teamCount, err2 := a.Srv().Store.Team().AnalyticsTeamCount(false)
teamCountChan <- store.StoreResult{Data: teamCount, NErr: err2}
close(teamCountChan)
}()
var teamsCount int64
g.Go(func() error {
var err error
if teamsCount, err = a.Srv().Store.Team().AnalyticsTeamCount(false); err != nil {
return model.NewAppError("GetAnalytics", "app.team.analytics_team_count.app_error", nil, err.Error(), http.StatusInternalServerError)
}
return nil
})
dailyActiveChan := make(chan store.StoreResult, 1)
go func() {
dailyActive, err2 := a.Srv().Store.User().AnalyticsActiveCount(DayMilliseconds, model.UserCountOptions{IncludeBotAccounts: false, IncludeDeleted: false})
dailyActiveChan <- store.StoreResult{Data: dailyActive, NErr: err2}
close(dailyActiveChan)
}()
var dailyActiveUsersCount int64
g.Go(func() error {
var err error
if dailyActiveUsersCount, err = a.Srv().Store.User().AnalyticsActiveCount(DayMilliseconds, model.UserCountOptions{IncludeBotAccounts: false, IncludeDeleted: false}); err != nil {
return model.NewAppError("GetAnalytics", "app.user.analytics_daily_active_users.app_error", nil, err.Error(), http.StatusInternalServerError)
}
return nil
})
monthlyActiveChan := make(chan store.StoreResult, 1)
go func() {
monthlyActive, err2 := a.Srv().Store.User().AnalyticsActiveCount(MonthMilliseconds, model.UserCountOptions{IncludeBotAccounts: false, IncludeDeleted: false})
monthlyActiveChan <- store.StoreResult{Data: monthlyActive, NErr: err2}
close(monthlyActiveChan)
}()
var monthlyActiveUsersCount int64
g.Go(func() error {
var err error
if monthlyActiveUsersCount, err = a.Srv().Store.User().AnalyticsActiveCount(MonthMilliseconds, model.UserCountOptions{IncludeBotAccounts: false, IncludeDeleted: false}); err != nil {
return model.NewAppError("GetAnalytics", "app.user.analytics_daily_active_users.app_error", nil, err.Error(), http.StatusInternalServerError)
}
return nil
})
r := <-openChan
if r.NErr != nil {
return nil, model.NewAppError("GetAnalytics", "app.channel.analytics_type_count.app_error", nil, r.NErr.Error(), http.StatusInternalServerError)
if err := g.Wait(); err != nil {
return nil, err.(*model.AppError)
}
rows[0].Value = float64(r.Data.(int64))
r = <-privateChan
if r.NErr != nil {
return nil, model.NewAppError("GetAnalytics", "app.channel.analytics_type_count.app_error", nil, r.NErr.Error(), http.StatusInternalServerError)
}
rows[1].Value = float64(r.Data.(int64))
rows[0].Value = float64(openChannelsCount)
rows[1].Value = float64(privateChannelsCount)
if postChan == nil {
if skipIntensiveQueries {
rows[2].Value = -1
} else {
r = <-postChan
if r.NErr != nil {
return nil, model.NewAppError("GetAnalytics", "app.post.analytics_posts_count.app_error", nil, r.NErr.Error(), http.StatusInternalServerError)
}
rows[2].Value = float64(r.Data.(int64))
rows[2].Value = float64(postsCount)
}
if userChan == nil {
if teamID == "" {
rows[3].Value = float64(systemUserCount)
rows[10].Value = float64(inactiveUsersCount)
} else {
r = <-userChan
if r.NErr != nil {
return nil, model.NewAppError("GetAnalytics", "app.user.get_total_users_count.app_error", nil, r.NErr.Error(), http.StatusInternalServerError)
}
rows[3].Value = float64(r.Data.(int64))
}
if userInactiveChan == nil {
rows[10].Value = -1
} else {
r = <-userInactiveChan
if r.NErr != nil {
return nil, model.NewAppError("GetAnalytics", "app.user.analytics_get_inactive_users_count.app_error", nil, r.NErr.Error(), http.StatusInternalServerError)
}
rows[10].Value = float64(r.Data.(int64))
rows[3].Value = float64(usersCount)
}
r = <-teamCountChan
if r.NErr != nil {
return nil, model.NewAppError("GetAnalytics", "app.team.analytics_team_count.app_error", nil, r.NErr.Error(), http.StatusInternalServerError)
}
rows[4].Value = float64(r.Data.(int64))
rows[4].Value = float64(teamsCount)
// If in HA mode then aggregate all the stats
if a.Cluster() != nil && *a.Config().ClusterSettings.Enable {
@@ -180,17 +171,8 @@ func (a *App) GetAnalytics(name string, teamID string) (model.AnalyticsRows, *mo
rows[7].Value = float64(a.Srv().Store.TotalReadDbConnections())
}
r = <-dailyActiveChan
if r.NErr != nil {
return nil, model.NewAppError("GetAnalytics", "app.user.analytics_daily_active_users.app_error", nil, r.NErr.Error(), http.StatusInternalServerError)
}
rows[8].Value = float64(r.Data.(int64))
r = <-monthlyActiveChan
if r.NErr != nil {
return nil, model.NewAppError("GetAnalytics", "app.user.analytics_daily_active_users.app_error", nil, r.NErr.Error(), http.StatusInternalServerError)
}
rows[9].Value = float64(r.Data.(int64))
rows[8].Value = float64(dailyActiveUsersCount)
rows[9].Value = float64(monthlyActiveUsersCount)
return rows, nil
} else if name == "bot_post_counts_day" {
@@ -244,96 +226,80 @@ func (a *App) GetAnalytics(name string, teamID string) (model.AnalyticsRows, *mo
rows[4] = &model.AnalyticsRow{Name: "command_count", Value: 0}
rows[5] = &model.AnalyticsRow{Name: "session_count", Value: 0}
iHookChan := make(chan store.StoreResult, 1)
go func() {
c, err2 := a.Srv().Store.Webhook().AnalyticsIncomingCount(teamID)
iHookChan <- store.StoreResult{Data: c, NErr: err2}
close(iHookChan)
}()
var g2 errgroup.Group
oHookChan := make(chan store.StoreResult, 1)
go func() {
c, err2 := a.Srv().Store.Webhook().AnalyticsOutgoingCount(teamID)
oHookChan <- store.StoreResult{Data: c, NErr: err2}
close(oHookChan)
}()
commandChan := make(chan store.StoreResult, 1)
go func() {
c, nErr := a.Srv().Store.Command().AnalyticsCommandCount(teamID)
commandChan <- store.StoreResult{Data: c, NErr: nErr}
close(commandChan)
}()
sessionChan := make(chan store.StoreResult, 1)
go func() {
count, err2 := a.Srv().Store.Session().AnalyticsSessionCount()
sessionChan <- store.StoreResult{Data: count, NErr: err2}
close(sessionChan)
}()
var fileChan chan store.StoreResult
var hashtagChan chan store.StoreResult
if !skipIntensiveQueries {
fileChan = make(chan store.StoreResult, 1)
go func() {
count, err2 := a.Srv().Store.Post().AnalyticsPostCount(teamID, true, false)
fileChan <- store.StoreResult{Data: count, NErr: err2}
close(fileChan)
}()
hashtagChan = make(chan store.StoreResult, 1)
go func() {
count, err2 := a.Srv().Store.Post().AnalyticsPostCount(teamID, false, true)
hashtagChan <- store.StoreResult{Data: count, NErr: err2}
close(hashtagChan)
}()
}
if fileChan == nil {
rows[0].Value = -1
} else {
r := <-fileChan
if r.NErr != nil {
return nil, model.NewAppError("GetAnalytics", "app.post.analytics_posts_count.app_error", nil, r.NErr.Error(), http.StatusInternalServerError)
var incomingWebhookCount int64
g2.Go(func() error {
var err error
if incomingWebhookCount, err = a.Srv().Store.Webhook().AnalyticsIncomingCount(teamID); err != nil {
return model.NewAppError("GetAnalytics", "app.webhooks.analytics_incoming_count.app_error", nil, err.Error(), http.StatusInternalServerError)
}
rows[0].Value = float64(r.Data.(int64))
return nil
})
var outgoingWebhookCount int64
g2.Go(func() error {
var err error
if outgoingWebhookCount, err = a.Srv().Store.Webhook().AnalyticsOutgoingCount(teamID); err != nil {
return model.NewAppError("GetAnalytics", "app.webhooks.analytics_outgoing_count.app_error", nil, err.Error(), http.StatusInternalServerError)
}
return nil
})
var commandsCount int64
g2.Go(func() error {
var err error
if commandsCount, err = a.Srv().Store.Command().AnalyticsCommandCount(teamID); err != nil {
return model.NewAppError("GetAnalytics", "app.analytics.getanalytics.internal_error", nil, err.Error(), http.StatusInternalServerError)
}
return nil
})
var sessionsCount int64
g2.Go(func() error {
var err error
if sessionsCount, err = a.Srv().Store.Session().AnalyticsSessionCount(); err != nil {
return model.NewAppError("GetAnalytics", "app.session.analytics_session_count.app_error", nil, err.Error(), http.StatusInternalServerError)
}
return nil
})
var filesCount int64
var hashtagsCount int64
if !skipIntensiveQueries {
g2.Go(func() error {
var err error
if filesCount, err = a.Srv().Store.Post().AnalyticsPostCount(teamID, true, false); err != nil {
return model.NewAppError("GetAnalytics", "app.post.analytics_posts_count.app_error", nil, err.Error(), http.StatusInternalServerError)
}
return nil
})
g2.Go(func() error {
var err error
if hashtagsCount, err = a.Srv().Store.Post().AnalyticsPostCount(teamID, false, true); err != nil {
return model.NewAppError("GetAnalytics", "app.post.analytics_posts_count.app_error", nil, err.Error(), http.StatusInternalServerError)
}
return nil
})
}
if hashtagChan == nil {
if err := g2.Wait(); err != nil {
return nil, err.(*model.AppError)
}
if skipIntensiveQueries {
rows[0].Value = -1
rows[1].Value = -1
} else {
r := <-hashtagChan
if r.NErr != nil {
return nil, model.NewAppError("GetAnalytics", "app.post.analytics_posts_count.app_error", nil, r.NErr.Error(), http.StatusInternalServerError)
}
rows[1].Value = float64(r.Data.(int64))
rows[0].Value = float64(filesCount)
rows[1].Value = float64(hashtagsCount)
}
r := <-iHookChan
if r.NErr != nil {
return nil, model.NewAppError("GetAnalytics", "app.webhooks.analytics_incoming_count.app_error", nil, r.NErr.Error(), http.StatusInternalServerError)
}
rows[2].Value = float64(r.Data.(int64))
r = <-oHookChan
if r.NErr != nil {
return nil, model.NewAppError("GetAnalytics", "app.webhooks.analytics_outgoing_count.app_error", nil, r.NErr.Error(), http.StatusInternalServerError)
}
rows[3].Value = float64(r.Data.(int64))
r = <-commandChan
if r.NErr != nil {
return nil, model.NewAppError("GetAnalytics", "app.analytics.getanalytics.internal_error", nil, r.NErr.Error(), http.StatusInternalServerError)
}
rows[4].Value = float64(r.Data.(int64))
r = <-sessionChan
if r.NErr != nil {
return nil, model.NewAppError("GetAnalytics", "app.session.analytics_session_count.app_error", nil, r.NErr.Error(), http.StatusInternalServerError)
}
rows[5].Value = float64(r.Data.(int64))
rows[2].Value = float64(incomingWebhookCount)
rows[3].Value = float64(outgoingWebhookCount)
rows[4].Value = float64(commandsCount)
rows[5].Value = float64(sessionsCount)
return rows, nil
}