1
0
mirror of https://github.com/muety/wakapi.git synced 2023-08-10 21:12:56 +03:00

fix: attempt to fix race condition when counting

This commit is contained in:
Ferdinand Mütsch 2021-04-30 17:19:17 +02:00
parent 8dc69c58cb
commit 0673c26043

View File

@ -3,7 +3,6 @@ package services
import ( import (
"github.com/emvi/logbuch" "github.com/emvi/logbuch"
"github.com/muety/wakapi/config" "github.com/muety/wakapi/config"
"go.uber.org/atomic"
"runtime" "runtime"
"strconv" "strconv"
"time" "time"
@ -17,7 +16,6 @@ type MiscService struct {
userService IUserService userService IUserService
summaryService ISummaryService summaryService ISummaryService
keyValueService IKeyValueService keyValueService IKeyValueService
jobCount atomic.Uint32
} }
func NewMiscService(userService IUserService, summaryService ISummaryService, keyValueService IKeyValueService) *MiscService { func NewMiscService(userService IUserService, summaryService ISummaryService, keyValueService IKeyValueService) *MiscService {
@ -51,27 +49,47 @@ func (srv *MiscService) ScheduleCountTotalTime() {
} }
func (srv *MiscService) runCountTotalTime() error { func (srv *MiscService) runCountTotalTime() error {
jobs := make(chan *CountTotalTimeJob) users, err := srv.userService.GetAll()
results := make(chan *CountTotalTimeResult) if err != nil {
return err
}
defer close(jobs) jobs := make(chan *CountTotalTimeJob, len(users))
results := make(chan *CountTotalTimeResult, len(users))
for _, u := range users {
jobs <- &CountTotalTimeJob{
UserID: u.ID,
NumJobs: len(users),
}
}
close(jobs)
for i := 0; i < runtime.NumCPU(); i++ { for i := 0; i < runtime.NumCPU(); i++ {
go srv.countTotalTimeWorker(jobs, results) go srv.countTotalTimeWorker(jobs, results)
} }
go srv.persistTotalTimeWorker(results) // persist
var i int
var total time.Duration
for i = 0; i < len(users); i++ {
result := <-results
total += result.Total
}
close(results)
// generate the jobs if err := srv.keyValueService.PutString(&models.KeyStringValue{
if users, err := srv.userService.GetAll(); err == nil { Key: config.KeyLatestTotalTime,
for _, u := range users { Value: total.String(),
jobs <- &CountTotalTimeJob{ }); err != nil {
UserID: u.ID, logbuch.Error("failed to save total time count: %v", err)
NumJobs: len(users), }
}
} if err := srv.keyValueService.PutString(&models.KeyStringValue{
} else { Key: config.KeyLatestTotalUsers,
return err Value: strconv.Itoa(i),
}); err != nil {
logbuch.Error("failed to save total users count: %v", err)
} }
return nil return nil
@ -87,32 +105,5 @@ func (srv *MiscService) countTotalTimeWorker(jobs <-chan *CountTotalTimeJob, res
Total: result.TotalTime(), Total: result.TotalTime(),
} }
} }
if srv.jobCount.Inc() == uint32(job.NumJobs) {
srv.jobCount.Store(0)
close(results)
}
}
}
func (srv *MiscService) persistTotalTimeWorker(results <-chan *CountTotalTimeResult) {
var c int
var total time.Duration
for result := range results {
total += result.Total
c++
}
if err := srv.keyValueService.PutString(&models.KeyStringValue{
Key: config.KeyLatestTotalTime,
Value: total.String(),
}); err != nil {
logbuch.Error("failed to save total time count: %v", err)
}
if err := srv.keyValueService.PutString(&models.KeyStringValue{
Key: config.KeyLatestTotalUsers,
Value: strconv.Itoa(c),
}); err != nil {
logbuch.Error("failed to save total users count: %v", err)
} }
} }