Metrics for shared channels (#26199)
* add metrics definitions for shared channels
Этот коммит содержится в:
@@ -6,6 +6,8 @@ package sharedchannel
|
||||
|
||||
import (
|
||||
mlog "github.com/mattermost/mattermost/server/public/shared/mlog"
|
||||
einterfaces "github.com/mattermost/mattermost/server/v8/einterfaces"
|
||||
|
||||
mock "github.com/stretchr/testify/mock"
|
||||
|
||||
model "github.com/mattermost/mattermost/server/public/model"
|
||||
@@ -50,6 +52,22 @@ func (_m *MockServerIface) Config() *model.Config {
|
||||
return r0
|
||||
}
|
||||
|
||||
// GetMetrics provides a mock function with given fields:
|
||||
func (_m *MockServerIface) GetMetrics() einterfaces.MetricsInterface {
|
||||
ret := _m.Called()
|
||||
|
||||
var r0 einterfaces.MetricsInterface
|
||||
if rf, ok := ret.Get(0).(func() einterfaces.MetricsInterface); ok {
|
||||
r0 = rf()
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(einterfaces.MetricsInterface)
|
||||
}
|
||||
}
|
||||
|
||||
return r0
|
||||
}
|
||||
|
||||
// GetRemoteClusterService provides a mock function with given fields:
|
||||
func (_m *MockServerIface) GetRemoteClusterService() remotecluster.RemoteClusterServiceIFace {
|
||||
ret := _m.Called()
|
||||
|
||||
@@ -14,6 +14,7 @@ import (
|
||||
"github.com/mattermost/mattermost/server/public/shared/mlog"
|
||||
"github.com/mattermost/mattermost/server/public/shared/request"
|
||||
"github.com/mattermost/mattermost/server/v8/channels/store"
|
||||
"github.com/mattermost/mattermost/server/v8/einterfaces"
|
||||
"github.com/mattermost/mattermost/server/v8/platform/services/remotecluster"
|
||||
"github.com/mattermost/mattermost/server/v8/platform/shared/filestore"
|
||||
)
|
||||
@@ -42,6 +43,7 @@ type ServerIface interface {
|
||||
GetStore() store.Store
|
||||
Log() *mlog.Logger
|
||||
GetRemoteClusterService() remotecluster.RemoteClusterServiceIFace
|
||||
GetMetrics() einterfaces.MetricsInterface
|
||||
}
|
||||
|
||||
type PlatformIface interface {
|
||||
|
||||
@@ -178,12 +178,25 @@ func (scs *Service) doSync() time.Duration {
|
||||
var task syncTask
|
||||
var ok bool
|
||||
var shortestWait time.Duration
|
||||
metrics := scs.server.GetMetrics()
|
||||
|
||||
if metrics != nil {
|
||||
scs.mux.Lock()
|
||||
size := len(scs.tasks)
|
||||
scs.mux.Unlock()
|
||||
metrics.ObserveSharedChannelsQueueSize(int64(size))
|
||||
}
|
||||
|
||||
for {
|
||||
task, ok, shortestWait = scs.removeOldestTask()
|
||||
if !ok {
|
||||
break
|
||||
}
|
||||
|
||||
if metrics != nil {
|
||||
metrics.ObserveSharedChannelsTaskInQueueDuration(time.Since(task.AddedAt).Seconds())
|
||||
}
|
||||
|
||||
if err := scs.processTask(task); err != nil {
|
||||
// put task back into map so it will update again
|
||||
if task.incRetry() {
|
||||
@@ -236,18 +249,22 @@ func (scs *Service) removeOldestTask() (syncTask, bool, time.Duration) {
|
||||
|
||||
// processTask updates one or more remote clusters with any new channel content.
|
||||
func (scs *Service) processTask(task syncTask) error {
|
||||
var err error
|
||||
var remotes []*model.RemoteCluster
|
||||
// map is used to ensure remotes don't get sync'd twice, such as when
|
||||
// they have the autoinvited flag and have explicitly subscribed to a channel.
|
||||
remotesMap := make(map[string]*model.RemoteCluster)
|
||||
|
||||
if task.remoteID == "" {
|
||||
filter := model.RemoteClusterQueryFilter{
|
||||
InChannel: task.channelID,
|
||||
OnlyConfirmed: true,
|
||||
}
|
||||
remotes, err = scs.server.GetStore().RemoteCluster().GetAll(filter)
|
||||
remotes, err := scs.server.GetStore().RemoteCluster().GetAll(filter)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, r := range remotes {
|
||||
remotesMap[r.RemoteId] = r
|
||||
}
|
||||
|
||||
// add all remotes that have the autoinvited option.
|
||||
filter = model.RemoteClusterQueryFilter{
|
||||
@@ -257,7 +274,9 @@ func (scs *Service) processTask(task syncTask) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
remotes = append(remotes, remotesAutoInvited...)
|
||||
for _, r := range remotesAutoInvited {
|
||||
remotesMap[r.RemoteId] = r
|
||||
}
|
||||
} else {
|
||||
rc, err := scs.server.GetStore().RemoteCluster().Get(task.remoteID)
|
||||
if err != nil {
|
||||
@@ -266,10 +285,10 @@ func (scs *Service) processTask(task syncTask) error {
|
||||
if !rc.IsOnline() {
|
||||
return fmt.Errorf("Failed updating shared channel '%s' for offline remote cluster '%s'", task.channelID, rc.DisplayName)
|
||||
}
|
||||
remotes = []*model.RemoteCluster{rc}
|
||||
remotesMap[rc.RemoteId] = rc
|
||||
}
|
||||
|
||||
for _, rc := range remotes {
|
||||
for _, rc := range remotesMap {
|
||||
rtask := task
|
||||
rtask.remoteID = rc.RemoteId
|
||||
if err := scs.syncForRemote(rtask, rc); err != nil {
|
||||
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/wiggin77/merror"
|
||||
|
||||
@@ -78,6 +79,18 @@ func (scs *Service) syncForRemote(task syncTask, rc *model.RemoteCluster) error
|
||||
return fmt.Errorf("cannot update remote cluster %s for channel id %s; Remote Cluster Service not enabled", rc.Name, task.channelID)
|
||||
}
|
||||
|
||||
metrics := scs.server.GetMetrics()
|
||||
|
||||
start := time.Now()
|
||||
var metricsRecorded bool
|
||||
defer func() {
|
||||
if !metricsRecorded && metrics != nil {
|
||||
metrics.IncrementSharedChannelsSyncCounter(rc.RemoteId)
|
||||
metrics.ObserveSharedChannelsSyncCollectionDuration(rc.RemoteId, time.Since(start).Seconds())
|
||||
metricsRecorded = true
|
||||
}
|
||||
}()
|
||||
|
||||
scr, err := scs.server.GetStore().SharedChannel().GetRemoteByIds(task.channelID, rc.RemoteId)
|
||||
if isNotFoundError(err) && rc.IsOptionFlagSet(model.BitflagOptionAutoInvited) {
|
||||
// if SharedChannelRemote not found and remote has autoinvite flag, create a scr for it, thus inviting the remote.
|
||||
@@ -175,12 +188,25 @@ func (scs *Service) syncForRemote(task syncTask, rc *model.RemoteCluster) error
|
||||
mlog.Int("attachments", len(sd.attachments)),
|
||||
)
|
||||
|
||||
if !metricsRecorded && metrics != nil {
|
||||
metrics.IncrementSharedChannelsSyncCounter(rc.RemoteId)
|
||||
metrics.ObserveSharedChannelsSyncCollectionDuration(rc.RemoteId, time.Since(start).Seconds())
|
||||
metricsRecorded = true
|
||||
}
|
||||
|
||||
return scs.sendSyncData(sd)
|
||||
}
|
||||
|
||||
// fetchUsersForSync populates the sync data with any channel users who updated their user profile
|
||||
// since the last sync.
|
||||
func (scs *Service) fetchUsersForSync(sd *syncData) error {
|
||||
start := time.Now()
|
||||
defer func() {
|
||||
if metrics := scs.server.GetMetrics(); metrics != nil {
|
||||
metrics.ObserveSharedChannelsSyncCollectionStepDuration(sd.rc.RemoteId, "Users", time.Since(start).Seconds())
|
||||
}
|
||||
}()
|
||||
|
||||
filter := model.GetUsersForSyncFilter{
|
||||
ChannelID: sd.task.channelID,
|
||||
Limit: MaxUsersPerSync,
|
||||
@@ -212,6 +238,13 @@ func (scs *Service) fetchUsersForSync(sd *syncData) error {
|
||||
|
||||
// fetchPostsForSync populates the sync data with any new or edited posts since the last sync.
|
||||
func (scs *Service) fetchPostsForSync(sd *syncData) error {
|
||||
start := time.Now()
|
||||
defer func() {
|
||||
if metrics := scs.server.GetMetrics(); metrics != nil {
|
||||
metrics.ObserveSharedChannelsSyncCollectionStepDuration(sd.rc.RemoteId, "Posts", time.Since(start).Seconds())
|
||||
}
|
||||
}()
|
||||
|
||||
options := model.GetPostsSinceForSyncOptions{
|
||||
ChannelId: sd.task.channelID,
|
||||
IncludeDeleted: true,
|
||||
@@ -288,6 +321,13 @@ func containsPost(posts []*model.Post, post *model.Post) bool {
|
||||
|
||||
// fetchReactionsForSync populates the sync data with any new reactions since the last sync.
|
||||
func (scs *Service) fetchReactionsForSync(sd *syncData) error {
|
||||
start := time.Now()
|
||||
defer func() {
|
||||
if metrics := scs.server.GetMetrics(); metrics != nil {
|
||||
metrics.ObserveSharedChannelsSyncCollectionStepDuration(sd.rc.RemoteId, "Reactions", time.Since(start).Seconds())
|
||||
}
|
||||
}()
|
||||
|
||||
merr := merror.New()
|
||||
for _, post := range sd.posts {
|
||||
// any reactions originating from the remote cluster are filtered out
|
||||
@@ -303,6 +343,13 @@ func (scs *Service) fetchReactionsForSync(sd *syncData) error {
|
||||
|
||||
// fetchPostUsersForSync populates the sync data with all users associated with posts.
|
||||
func (scs *Service) fetchPostUsersForSync(sd *syncData) error {
|
||||
start := time.Now()
|
||||
defer func() {
|
||||
if metrics := scs.server.GetMetrics(); metrics != nil {
|
||||
metrics.ObserveSharedChannelsSyncCollectionStepDuration(sd.rc.RemoteId, "PostUsers", time.Since(start).Seconds())
|
||||
}
|
||||
}()
|
||||
|
||||
sc, err := scs.server.GetStore().SharedChannel().Get(sd.task.channelID)
|
||||
if err != nil {
|
||||
return fmt.Errorf("cannot determine teamID: %w", err)
|
||||
@@ -367,6 +414,13 @@ func (scs *Service) fetchPostUsersForSync(sd *syncData) error {
|
||||
|
||||
// fetchPostAttachmentsForSync populates the sync data with any file attachments for new posts.
|
||||
func (scs *Service) fetchPostAttachmentsForSync(sd *syncData) error {
|
||||
start := time.Now()
|
||||
defer func() {
|
||||
if metrics := scs.server.GetMetrics(); metrics != nil {
|
||||
metrics.ObserveSharedChannelsSyncCollectionStepDuration(sd.rc.RemoteId, "Attachments", time.Since(start).Seconds())
|
||||
}
|
||||
}()
|
||||
|
||||
merr := merror.New()
|
||||
for _, post := range sd.posts {
|
||||
fis, err := scs.server.GetStore().FileInfo().GetForPost(post.Id, false, true, true)
|
||||
@@ -420,8 +474,14 @@ func (scs *Service) filterPostsForSync(sd *syncData) {
|
||||
// remote cluster.
|
||||
// The order of items sent is important: users -> attachments -> posts -> reactions -> profile images
|
||||
func (scs *Service) sendSyncData(sd *syncData) error {
|
||||
merr := merror.New()
|
||||
start := time.Now()
|
||||
defer func() {
|
||||
if metrics := scs.server.GetMetrics(); metrics != nil {
|
||||
metrics.ObserveSharedChannelsSyncSendDuration(sd.rc.RemoteId, time.Since(start).Seconds())
|
||||
}
|
||||
}()
|
||||
|
||||
merr := merror.New()
|
||||
sanitizeSyncData(sd)
|
||||
|
||||
// send users
|
||||
@@ -462,6 +522,13 @@ func (scs *Service) sendSyncData(sd *syncData) error {
|
||||
|
||||
// sendUserSyncData sends the collected user updates to the remote cluster.
|
||||
func (scs *Service) sendUserSyncData(sd *syncData) error {
|
||||
start := time.Now()
|
||||
defer func() {
|
||||
if metrics := scs.server.GetMetrics(); metrics != nil {
|
||||
metrics.ObserveSharedChannelsSyncSendStepDuration(sd.rc.RemoteId, "Users", time.Since(start).Seconds())
|
||||
}
|
||||
}()
|
||||
|
||||
msg := model.NewSyncMsg(sd.task.channelID)
|
||||
msg.Users = sd.users
|
||||
|
||||
@@ -504,6 +571,13 @@ func (scs *Service) sendAttachmentSyncData(sd *syncData) {
|
||||
|
||||
// sendPostSyncData sends the collected post updates to the remote cluster.
|
||||
func (scs *Service) sendPostSyncData(sd *syncData) error {
|
||||
start := time.Now()
|
||||
defer func() {
|
||||
if metrics := scs.server.GetMetrics(); metrics != nil {
|
||||
metrics.ObserveSharedChannelsSyncSendStepDuration(sd.rc.RemoteId, "Posts", time.Since(start).Seconds())
|
||||
}
|
||||
}()
|
||||
|
||||
msg := model.NewSyncMsg(sd.task.channelID)
|
||||
msg.Posts = sd.posts
|
||||
|
||||
@@ -525,6 +599,13 @@ func (scs *Service) sendPostSyncData(sd *syncData) error {
|
||||
|
||||
// sendReactionSyncData sends the collected reaction updates to the remote cluster.
|
||||
func (scs *Service) sendReactionSyncData(sd *syncData) error {
|
||||
start := time.Now()
|
||||
defer func() {
|
||||
if metrics := scs.server.GetMetrics(); metrics != nil {
|
||||
metrics.ObserveSharedChannelsSyncSendStepDuration(sd.rc.RemoteId, "Reactions", time.Since(start).Seconds())
|
||||
}
|
||||
}()
|
||||
|
||||
msg := model.NewSyncMsg(sd.task.channelID)
|
||||
msg.Reactions = sd.reactions
|
||||
|
||||
|
||||
Ссылка в новой задаче
Block a user