This reverts commit 0da249c651.
Этот коммит содержится в:
коммит произвёл
GitHub
родитель
d0724d8b00
Коммит
a55bd001b4
@@ -30,12 +30,6 @@ func RegisterComplianceInterface(f func(*App) einterfaces.ComplianceInterface) {
|
|||||||
complianceInterface = f
|
complianceInterface = f
|
||||||
}
|
}
|
||||||
|
|
||||||
var fixCRTChannelUnreadsJobInterface func(*Server) tjobs.FixCRTChannelUnreadsJobInterface
|
|
||||||
|
|
||||||
func RegisterFixCRTChannelUnreadsJobInterface(f func(*Server) tjobs.FixCRTChannelUnreadsJobInterface) {
|
|
||||||
fixCRTChannelUnreadsJobInterface = f
|
|
||||||
}
|
|
||||||
|
|
||||||
var dataRetentionInterface func(*App) einterfaces.DataRetentionInterface
|
var dataRetentionInterface func(*App) einterfaces.DataRetentionInterface
|
||||||
|
|
||||||
func RegisterDataRetentionInterface(f func(*App) einterfaces.DataRetentionInterface) {
|
func RegisterDataRetentionInterface(f func(*App) einterfaces.DataRetentionInterface) {
|
||||||
|
|||||||
@@ -1923,10 +1923,6 @@ func (s *Server) initJobs() {
|
|||||||
s.Jobs.ExtractContent = jobsExtractContentInterface(s)
|
s.Jobs.ExtractContent = jobsExtractContentInterface(s)
|
||||||
}
|
}
|
||||||
|
|
||||||
if fixCRTChannelUnreadsJobInterface != nil {
|
|
||||||
s.Jobs.FixCRTChannelUnreads = fixCRTChannelUnreadsJobInterface(s)
|
|
||||||
}
|
|
||||||
|
|
||||||
s.Jobs.InitWorkers()
|
s.Jobs.InitWorkers()
|
||||||
s.Jobs.InitSchedulers()
|
s.Jobs.InitSchedulers()
|
||||||
}
|
}
|
||||||
|
|||||||
16
i18n/en.json
16
i18n/en.json
@@ -7539,22 +7539,6 @@
|
|||||||
"id": "extract_content.worker.do_job.file_info",
|
"id": "extract_content.worker.do_job.file_info",
|
||||||
"translation": "Failed to get file information for content extraction."
|
"translation": "Failed to get file information for content extraction."
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"id": "fix_crt_channel_unreads.worker.do_job.get_bad_channel_memberships",
|
|
||||||
"translation": "Failed to get bad channel memberships"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "fix_crt_channel_unreads.worker.do_job.get_post_types",
|
|
||||||
"translation": "Failed to get unique post types"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "fix_crt_channel_unreads.worker.do_job.kill_orphan_jobs",
|
|
||||||
"translation": "Killing orphaned jobs"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "fix_crt_channel_unreads.worker.do_job.mark_channel_as_read",
|
|
||||||
"translation": "Failed to mark channel as read"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"id": "group_not_associated_to_synced_team",
|
"id": "group_not_associated_to_synced_team",
|
||||||
"translation": "Group cannot be associated to the channel until it is first associated to the parent group-synced team."
|
"translation": "Group cannot be associated to the channel until it is first associated to the parent group-synced team."
|
||||||
|
|||||||
@@ -39,7 +39,4 @@ import (
|
|||||||
|
|
||||||
// This is a placeholder so this package can be imported in Team Edition when it will be otherwise empty.
|
// This is a placeholder so this package can be imported in Team Edition when it will be otherwise empty.
|
||||||
_ "github.com/mattermost/mattermost-server/v6/jobs/extract_content"
|
_ "github.com/mattermost/mattermost-server/v6/jobs/extract_content"
|
||||||
|
|
||||||
// This is a placeholder so this package can be imported in Team Edition when it will be otherwise empty.
|
|
||||||
_ "github.com/mattermost/mattermost-server/v6/jobs/fix_crt_channel_unreads"
|
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,67 +0,0 @@
|
|||||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
|
||||||
// See LICENSE.txt for license information.
|
|
||||||
|
|
||||||
package fix_crt_channel_unreads
|
|
||||||
|
|
||||||
import (
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/mattermost/mattermost-server/v6/app"
|
|
||||||
"github.com/mattermost/mattermost-server/v6/model"
|
|
||||||
"github.com/mattermost/mattermost-server/v6/shared/mlog"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Scheduler struct {
|
|
||||||
App *app.App
|
|
||||||
}
|
|
||||||
|
|
||||||
func (i *FixCRTChannelUnreadsJobInterfaceImpl) MakeScheduler() model.Scheduler {
|
|
||||||
return &Scheduler{i.App}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Scheduler) Name() string {
|
|
||||||
return JobName + "Scheduler"
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Scheduler) JobType() string {
|
|
||||||
return model.JobTypeFixChannelUnreadsForCRT
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Scheduler) Enabled(cfg *model.Config) bool {
|
|
||||||
if _, err := s.App.Srv().Store.System().GetByName(model.MigrationKeyFixCRTChannelUnreads); err == nil {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Scheduler) NextScheduleTime(cfg *model.Config, now time.Time, pendingJobs bool, lastSuccessfulJob *model.Job) *time.Time {
|
|
||||||
nextTime := time.Now().Add(1 * time.Minute)
|
|
||||||
|
|
||||||
runningJobs, err := s.App.Srv().Store.Job().GetCountByStatusAndType(model.JobStatusInProgress, s.JobType())
|
|
||||||
if err != nil {
|
|
||||||
mlog.Error("Failed to get running jobs", mlog.Err(err))
|
|
||||||
runningJobs = 1
|
|
||||||
}
|
|
||||||
// if we have have pending or running jobs then schedule later
|
|
||||||
if pendingJobs || runningJobs > 0 {
|
|
||||||
nextTime = time.Now().Add(30 * time.Minute)
|
|
||||||
}
|
|
||||||
return &nextTime
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Scheduler) ScheduleJob(cfg *model.Config, pendingJobs bool, lastSuccessfulJob *model.Job) (*model.Job, *model.AppError) {
|
|
||||||
// if we have pending or running jobs then don't create a job
|
|
||||||
runningJobs, sErr := s.App.Srv().Store.Job().GetCountByStatusAndType(model.JobStatusInProgress, s.JobType())
|
|
||||||
if sErr != nil {
|
|
||||||
mlog.Error("Failed to get running jobs", mlog.Err(sErr))
|
|
||||||
}
|
|
||||||
if pendingJobs || runningJobs > 0 {
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
job, err := s.App.Srv().Jobs.CreateJob(model.JobTypeFixChannelUnreadsForCRT, map[string]string{})
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return job, nil
|
|
||||||
}
|
|
||||||
@@ -1,273 +0,0 @@
|
|||||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
|
||||||
// See LICENSE.txt for license information.
|
|
||||||
|
|
||||||
package fix_crt_channel_unreads
|
|
||||||
|
|
||||||
import (
|
|
||||||
"database/sql"
|
|
||||||
"net/http"
|
|
||||||
"strconv"
|
|
||||||
|
|
||||||
"github.com/mattermost/mattermost-server/v6/app"
|
|
||||||
"github.com/mattermost/mattermost-server/v6/jobs"
|
|
||||||
tjobs "github.com/mattermost/mattermost-server/v6/jobs/interfaces"
|
|
||||||
"github.com/mattermost/mattermost-server/v6/model"
|
|
||||||
"github.com/mattermost/mattermost-server/v6/shared/mlog"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
JobName = "FixCRTChannelUnreads"
|
|
||||||
)
|
|
||||||
|
|
||||||
type FixCRTChannelUnreadsWorker struct {
|
|
||||||
name string
|
|
||||||
stopChan chan struct{}
|
|
||||||
stoppedChan chan struct{}
|
|
||||||
jobsChan chan model.Job
|
|
||||||
jobServer *jobs.JobServer
|
|
||||||
app *app.App
|
|
||||||
}
|
|
||||||
|
|
||||||
type FixCRTChannelUnreadsJobInterfaceImpl struct {
|
|
||||||
App *app.App
|
|
||||||
}
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
app.RegisterFixCRTChannelUnreadsJobInterface(func(s *app.Server) tjobs.FixCRTChannelUnreadsJobInterface {
|
|
||||||
a := app.New(app.ServerConnector(s.Channels()))
|
|
||||||
return &FixCRTChannelUnreadsJobInterfaceImpl{a}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (i *FixCRTChannelUnreadsJobInterfaceImpl) MakeWorker() model.Worker {
|
|
||||||
|
|
||||||
return &FixCRTChannelUnreadsWorker{
|
|
||||||
name: JobName,
|
|
||||||
stopChan: make(chan struct{}),
|
|
||||||
stoppedChan: make(chan struct{}),
|
|
||||||
jobsChan: make(chan model.Job),
|
|
||||||
jobServer: i.App.Srv().Jobs,
|
|
||||||
app: i.App,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *FixCRTChannelUnreadsWorker) JobChannel() chan<- model.Job {
|
|
||||||
return w.jobsChan
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *FixCRTChannelUnreadsWorker) Run() {
|
|
||||||
mlog.Debug("Worker started", mlog.String("worker", w.name))
|
|
||||||
|
|
||||||
// kill all in-progress jobs in DB. This can happen if server
|
|
||||||
// was shut down incorrectly
|
|
||||||
olderJobs, err := w.app.Srv().Store.Job().GetAllByStatus(model.JobStatusInProgress)
|
|
||||||
if err == nil {
|
|
||||||
for _, j := range olderJobs {
|
|
||||||
if j.Type == model.JobTypeFixChannelUnreadsForCRT {
|
|
||||||
w.setJobError(
|
|
||||||
j,
|
|
||||||
model.NewAppError(w.name, "fix_crt_channel_unreads.worker.do_job.kill_orphan_jobs",
|
|
||||||
nil,
|
|
||||||
"killing orphan jobs",
|
|
||||||
http.StatusInternalServerError),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
defer func() {
|
|
||||||
mlog.Debug("Worker finished", mlog.String("worker", w.name))
|
|
||||||
close(w.stoppedChan)
|
|
||||||
}()
|
|
||||||
|
|
||||||
for {
|
|
||||||
select {
|
|
||||||
case <-w.stopChan:
|
|
||||||
mlog.Debug("Worker received stop signal", mlog.String("worker", w.name))
|
|
||||||
return
|
|
||||||
case job := <-w.jobsChan:
|
|
||||||
mlog.Debug("Worker received a new candidate job.", mlog.String("worker", w.name))
|
|
||||||
w.doJob(&job)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *FixCRTChannelUnreadsWorker) Stop() {
|
|
||||||
mlog.Debug("Worker stopping", mlog.String("worker", w.name))
|
|
||||||
close(w.stopChan)
|
|
||||||
<-w.stoppedChan
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *FixCRTChannelUnreadsWorker) doJob(job *model.Job) {
|
|
||||||
if claimed, err := w.jobServer.ClaimJob(job); err != nil {
|
|
||||||
mlog.Warn("Worker experienced an error while trying to claim job",
|
|
||||||
mlog.String("worker", w.name),
|
|
||||||
mlog.String("job_id", job.Id),
|
|
||||||
mlog.String("error", err.Error()))
|
|
||||||
return
|
|
||||||
} else if !claimed {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if _, err := w.app.Srv().Store.System().GetByName(model.MigrationKeyFixCRTChannelUnreads); err == nil {
|
|
||||||
mlog.Info("Worker: migration already done", mlog.String("worker", w.name), mlog.String("job_id", job.Id))
|
|
||||||
w.setJobSuccess(job)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
fixedBadCM := 0
|
|
||||||
checkedCM := 0
|
|
||||||
migrationDone := false
|
|
||||||
prevErr := false
|
|
||||||
channelID, userID := w.getProgressFromPreviousJobs(job)
|
|
||||||
if userID != "" && channelID != "" {
|
|
||||||
mlog.Info("Restarting from previous job run", mlog.String("ChannelID", channelID), mlog.String("UserID", userID))
|
|
||||||
}
|
|
||||||
shouldStop := false
|
|
||||||
for {
|
|
||||||
select {
|
|
||||||
case <-w.stopChan:
|
|
||||||
shouldStop = true
|
|
||||||
default:
|
|
||||||
shouldStop = false
|
|
||||||
}
|
|
||||||
if shouldStop {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
cms, sErr := w.app.Srv().Store.Channel().GetCRTUnfixedChannelMembershipsAfter(channelID, userID, 100)
|
|
||||||
if sErr != nil {
|
|
||||||
if sErr == sql.ErrNoRows {
|
|
||||||
migrationDone = true
|
|
||||||
break
|
|
||||||
}
|
|
||||||
mlog.Warn("Failed to get bad channel memberships",
|
|
||||||
mlog.String("worker", w.name),
|
|
||||||
mlog.String("job_id", job.Id),
|
|
||||||
mlog.String("error", sErr.Error()))
|
|
||||||
if prevErr {
|
|
||||||
w.updateProgress(job, channelID, userID)
|
|
||||||
w.setJobError(job, model.NewAppError(w.name, "fix_crt_channel_unreads.worker.do_job.get_bad_channel_memberships", nil, sErr.Error(), http.StatusInternalServerError))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
prevErr = true
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if len(cms) == 0 {
|
|
||||||
migrationDone = true
|
|
||||||
break
|
|
||||||
}
|
|
||||||
lastCM := cms[len(cms)-1]
|
|
||||||
channelID = lastCM.ChannelId
|
|
||||||
userID = lastCM.UserId
|
|
||||||
|
|
||||||
prevErr = false
|
|
||||||
cmToFix := make(map[string][]string)
|
|
||||||
for _, cm := range cms {
|
|
||||||
postTypes, err := w.app.Srv().Store.Post().GetUniquePostTypesSince(cm.ChannelId, cm.LastViewedAt)
|
|
||||||
if err != nil {
|
|
||||||
mlog.Warn("Failed to get unique unread posts",
|
|
||||||
mlog.String("worker", w.name),
|
|
||||||
mlog.String("job_id", job.Id),
|
|
||||||
mlog.String("error", err.Error()))
|
|
||||||
if prevErr {
|
|
||||||
w.updateProgress(job, cm.ChannelId, cm.UserId)
|
|
||||||
w.setJobError(job, model.NewAppError(w.name, "fix_crt_channel_unreads.worker.do_job.get_post_types", nil, err.Error(), http.StatusInternalServerError))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
prevErr = true
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if containsOnlyJoinLeaveMessages(postTypes) {
|
|
||||||
cmToFix[cm.UserId] = append(cmToFix[cm.UserId], cm.ChannelId)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
checkedCM += len(cms)
|
|
||||||
for uID, cIDs := range cmToFix {
|
|
||||||
_, err := w.app.Srv().Store.Channel().UpdateLastViewedAt(cIDs, uID, false)
|
|
||||||
if err != nil {
|
|
||||||
mlog.Warn("Worker experienced an error while trying to mark channel as read",
|
|
||||||
mlog.String("worker", w.name),
|
|
||||||
mlog.String("job_id", job.Id),
|
|
||||||
mlog.String("error", err.Error()))
|
|
||||||
if prevErr {
|
|
||||||
w.updateProgress(job, channelID, userID)
|
|
||||||
w.setJobError(job, model.NewAppError(w.name, "fix_crt_channel_unreads.worker.do_job.mark_channel_as_read", nil, err.Error(), http.StatusInternalServerError))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
prevErr = true
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
fixedBadCM += len(cIDs)
|
|
||||||
}
|
|
||||||
w.updateProgress(job, channelID, userID)
|
|
||||||
prevErr = false
|
|
||||||
}
|
|
||||||
|
|
||||||
if migrationDone {
|
|
||||||
system := model.System{
|
|
||||||
Name: model.MigrationKeyFixCRTChannelUnreads,
|
|
||||||
Value: "true",
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := w.app.Srv().Store.System().Save(&system); err != nil {
|
|
||||||
mlog.Critical("Failed to mark crt channel unreads migration job as completed.", mlog.Err(err))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
job.Data["BadChannelMembershipsFixed"] = strconv.Itoa(fixedBadCM)
|
|
||||||
job.Data["TotalChannelMembershipsChecked"] = strconv.Itoa(checkedCM)
|
|
||||||
w.updateData(job)
|
|
||||||
|
|
||||||
mlog.Info("Worker: Job is complete", mlog.String("worker", w.name), mlog.String("job_id", job.Id))
|
|
||||||
w.setJobSuccess(job)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *FixCRTChannelUnreadsWorker) setJobSuccess(job *model.Job) {
|
|
||||||
if err := w.app.Srv().Jobs.SetJobSuccess(job); err != nil {
|
|
||||||
mlog.Error("Worker: Failed to set success for job", mlog.String("worker", w.name), mlog.String("job_id", job.Id), mlog.String("error", err.Error()))
|
|
||||||
w.setJobError(job, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *FixCRTChannelUnreadsWorker) setJobError(job *model.Job, appError *model.AppError) {
|
|
||||||
if err := w.app.Srv().Jobs.SetJobError(job, appError); err != nil {
|
|
||||||
mlog.Error("Worker: Failed to set job error", mlog.String("worker", w.name), mlog.String("job_id", job.Id), mlog.String("error", err.Error()))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *FixCRTChannelUnreadsWorker) updateData(job *model.Job) {
|
|
||||||
if err := w.app.Srv().Jobs.UpdateInProgressJobData(job); err != nil {
|
|
||||||
mlog.Error("Worker: Failed to update job data", mlog.String("worker", w.name), mlog.String("job_id", job.Id), mlog.String("error", err.Error()))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *FixCRTChannelUnreadsWorker) updateProgress(job *model.Job, channelID, userID string) {
|
|
||||||
job.Data["ChannelID"] = channelID
|
|
||||||
job.Data["UserID"] = userID
|
|
||||||
w.updateData(job)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *FixCRTChannelUnreadsWorker) getProgressFromPreviousJobs(job *model.Job) (string, string) {
|
|
||||||
olderJob, err := w.app.Srv().Store.Job().GetNewestJobByStatusesAndType(
|
|
||||||
[]string{model.JobStatusCanceled, model.JobStatusCancelRequested, model.JobStatusSuccess, model.JobStatusError},
|
|
||||||
job.Type,
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
return "", ""
|
|
||||||
}
|
|
||||||
return olderJob.Data["ChannelID"], olderJob.Data["UserID"]
|
|
||||||
}
|
|
||||||
|
|
||||||
func containsOnlyJoinLeaveMessages(postTypes []string) bool {
|
|
||||||
for _, pt := range postTypes {
|
|
||||||
switch pt {
|
|
||||||
case model.PostTypeJoinLeave, model.PostTypeAddRemove,
|
|
||||||
model.PostTypeJoinChannel, model.PostTypeLeaveChannel,
|
|
||||||
model.PostTypeJoinTeam, model.PostTypeLeaveTeam,
|
|
||||||
model.PostTypeAddToChannel, model.PostTypeRemoveFromChannel,
|
|
||||||
model.PostTypeAddToTeam, model.PostTypeRemoveFromTeam:
|
|
||||||
default:
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
|
||||||
// See LICENSE.txt for license information.
|
|
||||||
|
|
||||||
package interfaces
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/mattermost/mattermost-server/v6/model"
|
|
||||||
)
|
|
||||||
|
|
||||||
type FixCRTChannelUnreadsJobInterface interface {
|
|
||||||
MakeWorker() model.Worker
|
|
||||||
MakeScheduler() model.Scheduler
|
|
||||||
}
|
|
||||||
@@ -198,13 +198,6 @@ func (watcher *Watcher) PollAndNotify() {
|
|||||||
default:
|
default:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if job.Type == model.JobTypeFixChannelUnreadsForCRT {
|
|
||||||
if watcher.workers.FixCRTChannelUnreads != nil {
|
|
||||||
select {
|
|
||||||
case watcher.workers.FixCRTChannelUnreads.JobChannel() <- *job:
|
|
||||||
default:
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -101,10 +101,6 @@ func (srv *JobServer) InitSchedulers() error {
|
|||||||
schedulers.schedulers = append(schedulers.schedulers, exportDeleteInterface.MakeScheduler())
|
schedulers.schedulers = append(schedulers.schedulers, exportDeleteInterface.MakeScheduler())
|
||||||
}
|
}
|
||||||
|
|
||||||
if fixCRTChannelUnreadsInterface := srv.FixCRTChannelUnreads; fixCRTChannelUnreadsInterface != nil {
|
|
||||||
schedulers.schedulers = append(schedulers.schedulers, fixCRTChannelUnreadsInterface.MakeScheduler())
|
|
||||||
}
|
|
||||||
|
|
||||||
schedulers.nextRunTimes = make([]*time.Time, len(schedulers.schedulers))
|
schedulers.nextRunTimes = make([]*time.Time, len(schedulers.schedulers))
|
||||||
srv.schedulers = schedulers
|
srv.schedulers = schedulers
|
||||||
|
|
||||||
|
|||||||
@@ -37,7 +37,6 @@ type JobServer struct {
|
|||||||
Cloud ejobs.CloudJobInterface
|
Cloud ejobs.CloudJobInterface
|
||||||
ResendInvitationEmails ejobs.ResendInvitationEmailJobInterface
|
ResendInvitationEmails ejobs.ResendInvitationEmailJobInterface
|
||||||
ExtractContent tjobs.ExtractContentInterface
|
ExtractContent tjobs.ExtractContentInterface
|
||||||
FixCRTChannelUnreads tjobs.FixCRTChannelUnreadsJobInterface
|
|
||||||
|
|
||||||
// mut is used to protect the following fields from concurrent access.
|
// mut is used to protect the following fields from concurrent access.
|
||||||
mut sync.Mutex
|
mut sync.Mutex
|
||||||
|
|||||||
@@ -33,7 +33,6 @@ type Workers struct {
|
|||||||
Cloud model.Worker
|
Cloud model.Worker
|
||||||
ResendInvitationEmail model.Worker
|
ResendInvitationEmail model.Worker
|
||||||
ExtractContent model.Worker
|
ExtractContent model.Worker
|
||||||
FixCRTChannelUnreads model.Worker
|
|
||||||
|
|
||||||
listenerId string
|
listenerId string
|
||||||
running bool
|
running bool
|
||||||
@@ -130,10 +129,6 @@ func (srv *JobServer) InitWorkers() error {
|
|||||||
workers.ExtractContent = extractContentInterface.MakeWorker()
|
workers.ExtractContent = extractContentInterface.MakeWorker()
|
||||||
}
|
}
|
||||||
|
|
||||||
if fixCRTChannelUnreads := srv.FixCRTChannelUnreads; fixCRTChannelUnreads != nil {
|
|
||||||
workers.FixCRTChannelUnreads = fixCRTChannelUnreads.MakeWorker()
|
|
||||||
}
|
|
||||||
|
|
||||||
srv.workers = workers
|
srv.workers = workers
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
@@ -216,10 +211,6 @@ func (workers *Workers) Start() {
|
|||||||
go workers.ExtractContent.Run()
|
go workers.ExtractContent.Run()
|
||||||
}
|
}
|
||||||
|
|
||||||
if workers.FixCRTChannelUnreads != nil {
|
|
||||||
go workers.FixCRTChannelUnreads.Run()
|
|
||||||
}
|
|
||||||
|
|
||||||
go workers.Watcher.Start()
|
go workers.Watcher.Start()
|
||||||
|
|
||||||
workers.listenerId = workers.ConfigService.AddConfigListener(workers.handleConfigChange)
|
workers.listenerId = workers.ConfigService.AddConfigListener(workers.handleConfigChange)
|
||||||
@@ -357,10 +348,6 @@ func (workers *Workers) Stop() {
|
|||||||
workers.ExtractContent.Stop()
|
workers.ExtractContent.Stop()
|
||||||
}
|
}
|
||||||
|
|
||||||
if workers.FixCRTChannelUnreads != nil {
|
|
||||||
workers.FixCRTChannelUnreads.Stop()
|
|
||||||
}
|
|
||||||
|
|
||||||
workers.running = false
|
workers.running = false
|
||||||
|
|
||||||
mlog.Info("Stopped workers")
|
mlog.Info("Stopped workers")
|
||||||
|
|||||||
@@ -27,7 +27,6 @@ const (
|
|||||||
JobTypeCloud = "cloud"
|
JobTypeCloud = "cloud"
|
||||||
JobTypeResendInvitationEmail = "resend_invitation_email"
|
JobTypeResendInvitationEmail = "resend_invitation_email"
|
||||||
JobTypeExtractContent = "extract_content"
|
JobTypeExtractContent = "extract_content"
|
||||||
JobTypeFixChannelUnreadsForCRT = "fix_channel_unreads_for_crt"
|
|
||||||
|
|
||||||
JobStatusPending = "pending"
|
JobStatusPending = "pending"
|
||||||
JobStatusInProgress = "in_progress"
|
JobStatusInProgress = "in_progress"
|
||||||
@@ -56,7 +55,6 @@ var AllJobTypes = [...]string{
|
|||||||
JobTypeExportDelete,
|
JobTypeExportDelete,
|
||||||
JobTypeCloud,
|
JobTypeCloud,
|
||||||
JobTypeExtractContent,
|
JobTypeExtractContent,
|
||||||
JobTypeFixChannelUnreadsForCRT,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type Job struct {
|
type Job struct {
|
||||||
@@ -99,7 +97,6 @@ func (j *Job) IsValid() *AppError {
|
|||||||
case JobTypeCloud:
|
case JobTypeCloud:
|
||||||
case JobTypeResendInvitationEmail:
|
case JobTypeResendInvitationEmail:
|
||||||
case JobTypeExtractContent:
|
case JobTypeExtractContent:
|
||||||
case JobTypeFixChannelUnreadsForCRT:
|
|
||||||
default:
|
default:
|
||||||
return NewAppError("Job.IsValid", "model.job.is_valid.type.app_error", nil, "id="+j.Id, http.StatusBadRequest)
|
return NewAppError("Job.IsValid", "model.job.is_valid.type.app_error", nil, "id="+j.Id, http.StatusBadRequest)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,6 +35,5 @@ const (
|
|||||||
MigrationKeyAddTestEmailAncillaryPermission = "test_email_ancillary_permission"
|
MigrationKeyAddTestEmailAncillaryPermission = "test_email_ancillary_permission"
|
||||||
MigrationKeyAddAboutSubsectionPermissions = "about_subsection_permissions"
|
MigrationKeyAddAboutSubsectionPermissions = "about_subsection_permissions"
|
||||||
MigrationKeyAddIntegrationsSubsectionPermissions = "integrations_subsection_permissions"
|
MigrationKeyAddIntegrationsSubsectionPermissions = "integrations_subsection_permissions"
|
||||||
MigrationKeyFixCRTChannelUnreads = "fix_crt_channel_unreads"
|
|
||||||
MigrationKeyAddPlaybooksPermissions = "playbooks_permissions"
|
MigrationKeyAddPlaybooksPermissions = "playbooks_permissions"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1015,24 +1015,6 @@ func (s *OpenTracingLayerChannelStore) GetByNames(team_id string, names []string
|
|||||||
return result, err
|
return result, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *OpenTracingLayerChannelStore) GetCRTUnfixedChannelMembershipsAfter(channelID string, userID string, count int) ([]model.ChannelMember, error) {
|
|
||||||
origCtx := s.Root.Store.Context()
|
|
||||||
span, newCtx := tracing.StartSpanWithParentByContext(s.Root.Store.Context(), "ChannelStore.GetCRTUnfixedChannelMembershipsAfter")
|
|
||||||
s.Root.Store.SetContext(newCtx)
|
|
||||||
defer func() {
|
|
||||||
s.Root.Store.SetContext(origCtx)
|
|
||||||
}()
|
|
||||||
|
|
||||||
defer span.Finish()
|
|
||||||
result, err := s.ChannelStore.GetCRTUnfixedChannelMembershipsAfter(channelID, userID, count)
|
|
||||||
if err != nil {
|
|
||||||
span.LogFields(spanlog.Error(err))
|
|
||||||
ext.Error.Set(span, true)
|
|
||||||
}
|
|
||||||
|
|
||||||
return result, err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *OpenTracingLayerChannelStore) GetChannelCounts(teamID string, userID string) (*model.ChannelCounts, error) {
|
func (s *OpenTracingLayerChannelStore) GetChannelCounts(teamID string, userID string) (*model.ChannelCounts, error) {
|
||||||
origCtx := s.Root.Store.Context()
|
origCtx := s.Root.Store.Context()
|
||||||
span, newCtx := tracing.StartSpanWithParentByContext(s.Root.Store.Context(), "ChannelStore.GetChannelCounts")
|
span, newCtx := tracing.StartSpanWithParentByContext(s.Root.Store.Context(), "ChannelStore.GetChannelCounts")
|
||||||
@@ -5646,24 +5628,6 @@ func (s *OpenTracingLayerPostStore) GetSingle(id string, inclDeleted bool) (*mod
|
|||||||
return result, err
|
return result, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *OpenTracingLayerPostStore) GetUniquePostTypesSince(channelId string, timestamp int64) ([]string, error) {
|
|
||||||
origCtx := s.Root.Store.Context()
|
|
||||||
span, newCtx := tracing.StartSpanWithParentByContext(s.Root.Store.Context(), "PostStore.GetUniquePostTypesSince")
|
|
||||||
s.Root.Store.SetContext(newCtx)
|
|
||||||
defer func() {
|
|
||||||
s.Root.Store.SetContext(origCtx)
|
|
||||||
}()
|
|
||||||
|
|
||||||
defer span.Finish()
|
|
||||||
result, err := s.PostStore.GetUniquePostTypesSince(channelId, timestamp)
|
|
||||||
if err != nil {
|
|
||||||
span.LogFields(spanlog.Error(err))
|
|
||||||
ext.Error.Set(span, true)
|
|
||||||
}
|
|
||||||
|
|
||||||
return result, err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *OpenTracingLayerPostStore) HasAutoResponsePostByUserSince(options model.GetPostsSinceOptions, userId string) (bool, error) {
|
func (s *OpenTracingLayerPostStore) HasAutoResponsePostByUserSince(options model.GetPostsSinceOptions, userId string) (bool, error) {
|
||||||
origCtx := s.Root.Store.Context()
|
origCtx := s.Root.Store.Context()
|
||||||
span, newCtx := tracing.StartSpanWithParentByContext(s.Root.Store.Context(), "PostStore.HasAutoResponsePostByUserSince")
|
span, newCtx := tracing.StartSpanWithParentByContext(s.Root.Store.Context(), "PostStore.HasAutoResponsePostByUserSince")
|
||||||
|
|||||||
@@ -1129,27 +1129,6 @@ func (s *RetryLayerChannelStore) GetByNames(team_id string, names []string, allo
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *RetryLayerChannelStore) GetCRTUnfixedChannelMembershipsAfter(channelID string, userID string, count int) ([]model.ChannelMember, error) {
|
|
||||||
|
|
||||||
tries := 0
|
|
||||||
for {
|
|
||||||
result, err := s.ChannelStore.GetCRTUnfixedChannelMembershipsAfter(channelID, userID, count)
|
|
||||||
if err == nil {
|
|
||||||
return result, nil
|
|
||||||
}
|
|
||||||
if !isRepeatableError(err) {
|
|
||||||
return result, err
|
|
||||||
}
|
|
||||||
tries++
|
|
||||||
if tries >= 3 {
|
|
||||||
err = errors.Wrap(err, "giving up after 3 consecutive repeatable transaction failures")
|
|
||||||
return result, err
|
|
||||||
}
|
|
||||||
timepkg.Sleep(100 * timepkg.Millisecond)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *RetryLayerChannelStore) GetChannelCounts(teamID string, userID string) (*model.ChannelCounts, error) {
|
func (s *RetryLayerChannelStore) GetChannelCounts(teamID string, userID string) (*model.ChannelCounts, error) {
|
||||||
|
|
||||||
tries := 0
|
tries := 0
|
||||||
@@ -6385,27 +6364,6 @@ func (s *RetryLayerPostStore) GetSingle(id string, inclDeleted bool) (*model.Pos
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *RetryLayerPostStore) GetUniquePostTypesSince(channelId string, timestamp int64) ([]string, error) {
|
|
||||||
|
|
||||||
tries := 0
|
|
||||||
for {
|
|
||||||
result, err := s.PostStore.GetUniquePostTypesSince(channelId, timestamp)
|
|
||||||
if err == nil {
|
|
||||||
return result, nil
|
|
||||||
}
|
|
||||||
if !isRepeatableError(err) {
|
|
||||||
return result, err
|
|
||||||
}
|
|
||||||
tries++
|
|
||||||
if tries >= 3 {
|
|
||||||
err = errors.Wrap(err, "giving up after 3 consecutive repeatable transaction failures")
|
|
||||||
return result, err
|
|
||||||
}
|
|
||||||
timepkg.Sleep(100 * timepkg.Millisecond)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *RetryLayerPostStore) HasAutoResponsePostByUserSince(options model.GetPostsSinceOptions, userId string) (bool, error) {
|
func (s *RetryLayerPostStore) HasAutoResponsePostByUserSince(options model.GetPostsSinceOptions, userId string) (bool, error) {
|
||||||
|
|
||||||
tries := 0
|
tries := 0
|
||||||
|
|||||||
@@ -3704,32 +3704,3 @@ func (s SqlChannelStore) GetTeamForChannel(channelID string) (*model.Team, error
|
|||||||
}
|
}
|
||||||
return &team, nil
|
return &team, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s SqlChannelStore) GetCRTUnfixedChannelMembershipsAfter(channelID, userID string, count int) ([]model.ChannelMember, error) {
|
|
||||||
// we want both channelID and userID, or neither of them specified
|
|
||||||
if (userID == "" || channelID == "") && (channelID != userID) {
|
|
||||||
return nil, fmt.Errorf("channelID=%q userID=%q, got one empty param, both need to be empty or specified", channelID, userID)
|
|
||||||
}
|
|
||||||
getUnfixedCMQuery := `
|
|
||||||
SELECT ChannelMembers.*
|
|
||||||
FROM ChannelMembers, Channels
|
|
||||||
WHERE ChannelId = Id AND (ChannelMembers.UserId, ChannelMembers.ChannelId) > (:userId, :channelId) AND Channels.TotalMsgCountRoot > ChannelMembers.MsgCountRoot
|
|
||||||
ORDER BY UserId, ChannelId
|
|
||||||
LIMIT :count;
|
|
||||||
`
|
|
||||||
if userID == "" && channelID == "" {
|
|
||||||
getUnfixedCMQuery = `
|
|
||||||
SELECT ChannelMembers.*
|
|
||||||
FROM ChannelMembers, Channels
|
|
||||||
WHERE ChannelId = Id AND Channels.TotalMsgCountRoot > ChannelMembers.MsgCountRoot
|
|
||||||
ORDER BY UserId, ChannelId
|
|
||||||
LIMIT :count;
|
|
||||||
`
|
|
||||||
}
|
|
||||||
var dbMembers channelMemberWithSchemeRolesList
|
|
||||||
|
|
||||||
if _, err := s.GetReplica().Select(&dbMembers, getUnfixedCMQuery, map[string]interface{}{"channelId": channelID, "userId": userID, "count": count}); err != nil {
|
|
||||||
return nil, errors.Wrapf(err, "failed to get %d ChannelMembers after channelId=%q and userId=%q", count, channelID, userID)
|
|
||||||
}
|
|
||||||
return dbMembers.ToModel(), nil
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -2734,23 +2734,3 @@ func (s *SqlPostStore) updateThreadsFromPosts(transaction *sqlxTxWrapper, posts
|
|||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetUniquePostTypesSince returns the unique post types in a channel after the given timestamp
|
|
||||||
func (s *SqlPostStore) GetUniquePostTypesSince(channelId string, timestamp int64) ([]string, error) {
|
|
||||||
query, args, err := s.getQueryBuilder().
|
|
||||||
Select("DISTINCT Type").
|
|
||||||
From("Posts").
|
|
||||||
Where(sq.And{
|
|
||||||
sq.Eq{"ChannelId": channelId},
|
|
||||||
sq.GtOrEq{"CreateAt": timestamp},
|
|
||||||
sq.Eq{"DeleteAt": 0},
|
|
||||||
}).ToSql()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
types := []string{}
|
|
||||||
if err := s.GetReplicaX().Select(&types, query, args...); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return types, nil
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -275,9 +275,6 @@ type ChannelStore interface {
|
|||||||
SetShared(channelId string, shared bool) error
|
SetShared(channelId string, shared bool) error
|
||||||
// GetTeamForChannel returns the team for a given channelID.
|
// GetTeamForChannel returns the team for a given channelID.
|
||||||
GetTeamForChannel(channelID string) (*model.Team, error)
|
GetTeamForChannel(channelID string) (*model.Team, error)
|
||||||
|
|
||||||
//GetCRTUnfixedChannelMembershipsAfter gets CRT unfixed channel memberships after the given channelID and userID
|
|
||||||
GetCRTUnfixedChannelMembershipsAfter(channelID string, userID string, count int) ([]model.ChannelMember, error)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type ChannelMemberHistoryStore interface {
|
type ChannelMemberHistoryStore interface {
|
||||||
@@ -361,9 +358,6 @@ type PostStore interface {
|
|||||||
GetOldestEntityCreationTime() (int64, error)
|
GetOldestEntityCreationTime() (int64, error)
|
||||||
HasAutoResponsePostByUserSince(options model.GetPostsSinceOptions, userId string) (bool, error)
|
HasAutoResponsePostByUserSince(options model.GetPostsSinceOptions, userId string) (bool, error)
|
||||||
GetPostsSinceForSync(options model.GetPostsSinceForSyncOptions, cursor model.GetPostsSinceForSyncCursor, limit int) ([]*model.Post, model.GetPostsSinceForSyncCursor, error)
|
GetPostsSinceForSync(options model.GetPostsSinceForSyncOptions, cursor model.GetPostsSinceForSyncCursor, limit int) ([]*model.Post, model.GetPostsSinceForSyncCursor, error)
|
||||||
|
|
||||||
// GetUniquePostTypesSince returns the unique post types in a channel after the given timestamp
|
|
||||||
GetUniquePostTypesSince(channelId string, timestamp int64) ([]string, error)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type UserStore interface {
|
type UserStore interface {
|
||||||
|
|||||||
@@ -582,29 +582,6 @@ func (_m *ChannelStore) GetByNames(team_id string, names []string, allowFromCach
|
|||||||
return r0, r1
|
return r0, r1
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetCRTUnfixedChannelMembershipsAfter provides a mock function with given fields: channelID, userID, count
|
|
||||||
func (_m *ChannelStore) GetCRTUnfixedChannelMembershipsAfter(channelID string, userID string, count int) ([]model.ChannelMember, error) {
|
|
||||||
ret := _m.Called(channelID, userID, count)
|
|
||||||
|
|
||||||
var r0 []model.ChannelMember
|
|
||||||
if rf, ok := ret.Get(0).(func(string, string, int) []model.ChannelMember); ok {
|
|
||||||
r0 = rf(channelID, userID, count)
|
|
||||||
} else {
|
|
||||||
if ret.Get(0) != nil {
|
|
||||||
r0 = ret.Get(0).([]model.ChannelMember)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var r1 error
|
|
||||||
if rf, ok := ret.Get(1).(func(string, string, int) error); ok {
|
|
||||||
r1 = rf(channelID, userID, count)
|
|
||||||
} else {
|
|
||||||
r1 = ret.Error(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
return r0, r1
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetChannelCounts provides a mock function with given fields: teamID, userID
|
// GetChannelCounts provides a mock function with given fields: teamID, userID
|
||||||
func (_m *ChannelStore) GetChannelCounts(teamID string, userID string) (*model.ChannelCounts, error) {
|
func (_m *ChannelStore) GetChannelCounts(teamID string, userID string) (*model.ChannelCounts, error) {
|
||||||
ret := _m.Called(teamID, userID)
|
ret := _m.Called(teamID, userID)
|
||||||
|
|||||||
@@ -635,29 +635,6 @@ func (_m *PostStore) GetSingle(id string, inclDeleted bool) (*model.Post, error)
|
|||||||
return r0, r1
|
return r0, r1
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetUniquePostTypesSince provides a mock function with given fields: channelId, timestamp
|
|
||||||
func (_m *PostStore) GetUniquePostTypesSince(channelId string, timestamp int64) ([]string, error) {
|
|
||||||
ret := _m.Called(channelId, timestamp)
|
|
||||||
|
|
||||||
var r0 []string
|
|
||||||
if rf, ok := ret.Get(0).(func(string, int64) []string); ok {
|
|
||||||
r0 = rf(channelId, timestamp)
|
|
||||||
} else {
|
|
||||||
if ret.Get(0) != nil {
|
|
||||||
r0 = ret.Get(0).([]string)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var r1 error
|
|
||||||
if rf, ok := ret.Get(1).(func(string, int64) error); ok {
|
|
||||||
r1 = rf(channelId, timestamp)
|
|
||||||
} else {
|
|
||||||
r1 = ret.Error(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
return r0, r1
|
|
||||||
}
|
|
||||||
|
|
||||||
// HasAutoResponsePostByUserSince provides a mock function with given fields: options, userId
|
// HasAutoResponsePostByUserSince provides a mock function with given fields: options, userId
|
||||||
func (_m *PostStore) HasAutoResponsePostByUserSince(options model.GetPostsSinceOptions, userId string) (bool, error) {
|
func (_m *PostStore) HasAutoResponsePostByUserSince(options model.GetPostsSinceOptions, userId string) (bool, error) {
|
||||||
ret := _m.Called(options, userId)
|
ret := _m.Called(options, userId)
|
||||||
|
|||||||
@@ -949,22 +949,6 @@ func (s *TimerLayerChannelStore) GetByNames(team_id string, names []string, allo
|
|||||||
return result, err
|
return result, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *TimerLayerChannelStore) GetCRTUnfixedChannelMembershipsAfter(channelID string, userID string, count int) ([]model.ChannelMember, error) {
|
|
||||||
start := timemodule.Now()
|
|
||||||
|
|
||||||
result, err := s.ChannelStore.GetCRTUnfixedChannelMembershipsAfter(channelID, userID, count)
|
|
||||||
|
|
||||||
elapsed := float64(timemodule.Since(start)) / float64(timemodule.Second)
|
|
||||||
if s.Root.Metrics != nil {
|
|
||||||
success := "false"
|
|
||||||
if err == nil {
|
|
||||||
success = "true"
|
|
||||||
}
|
|
||||||
s.Root.Metrics.ObserveStoreMethodDuration("ChannelStore.GetCRTUnfixedChannelMembershipsAfter", success, elapsed)
|
|
||||||
}
|
|
||||||
return result, err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *TimerLayerChannelStore) GetChannelCounts(teamID string, userID string) (*model.ChannelCounts, error) {
|
func (s *TimerLayerChannelStore) GetChannelCounts(teamID string, userID string) (*model.ChannelCounts, error) {
|
||||||
start := timemodule.Now()
|
start := timemodule.Now()
|
||||||
|
|
||||||
@@ -5114,22 +5098,6 @@ func (s *TimerLayerPostStore) GetSingle(id string, inclDeleted bool) (*model.Pos
|
|||||||
return result, err
|
return result, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *TimerLayerPostStore) GetUniquePostTypesSince(channelId string, timestamp int64) ([]string, error) {
|
|
||||||
start := timemodule.Now()
|
|
||||||
|
|
||||||
result, err := s.PostStore.GetUniquePostTypesSince(channelId, timestamp)
|
|
||||||
|
|
||||||
elapsed := float64(timemodule.Since(start)) / float64(timemodule.Second)
|
|
||||||
if s.Root.Metrics != nil {
|
|
||||||
success := "false"
|
|
||||||
if err == nil {
|
|
||||||
success = "true"
|
|
||||||
}
|
|
||||||
s.Root.Metrics.ObserveStoreMethodDuration("PostStore.GetUniquePostTypesSince", success, elapsed)
|
|
||||||
}
|
|
||||||
return result, err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *TimerLayerPostStore) HasAutoResponsePostByUserSince(options model.GetPostsSinceOptions, userId string) (bool, error) {
|
func (s *TimerLayerPostStore) HasAutoResponsePostByUserSince(options model.GetPostsSinceOptions, userId string) (bool, error) {
|
||||||
start := timemodule.Now()
|
start := timemodule.Now()
|
||||||
|
|
||||||
|
|||||||
Ссылка в новой задаче
Block a user