359 lines
9.4 KiB
Go
359 lines
9.4 KiB
Go
package service
|
||
|
||
import (
|
||
"context"
|
||
"fmt"
|
||
"sync"
|
||
"time"
|
||
|
||
"go-common/app/admin/ep/marthe/model"
|
||
"go-common/library/ecode"
|
||
"go-common/library/log"
|
||
|
||
"github.com/satori/go.uuid"
|
||
)
|
||
|
||
// RunVersions Run Versions.
|
||
func (s *Service) RunVersions(buglyVersionID int64) (rep map[string]interface{}, err error) {
|
||
lock := s.getBatchRunLock(buglyVersionID)
|
||
lock.Lock()
|
||
defer lock.Unlock()
|
||
|
||
var (
|
||
buglyRunVersions []*model.BuglyVersion
|
||
uid string
|
||
isEnableRun bool
|
||
)
|
||
|
||
// 获取可以跑的版本号list
|
||
if buglyRunVersions, err = s.GetBatchRunVersions(); err != nil {
|
||
log.Error("GetBatchRunVersions err(%v) ", err)
|
||
return
|
||
}
|
||
|
||
for _, buglyRunVersion := range buglyRunVersions {
|
||
if buglyRunVersion.ID == buglyVersionID {
|
||
isEnableRun = true
|
||
uid = uuid.NewV4().String()
|
||
|
||
// 插入batchrun表
|
||
buglyBatchRun := &model.BuglyBatchRun{
|
||
BuglyVersionID: buglyRunVersion.ID,
|
||
Version: buglyRunVersion.Version,
|
||
BatchID: uid,
|
||
Status: model.BuglyBatchRunStatusRunning,
|
||
}
|
||
|
||
if err = s.dao.InsertBuglyBatchRun(buglyBatchRun); err != nil {
|
||
return
|
||
}
|
||
|
||
s.batchRunCache.Do(context.Background(), func(ctx context.Context) {
|
||
if err = s.runPerVersion(uid, buglyRunVersion); err != nil {
|
||
log.Error("runPerVersion uid(%s) version(%s) err(%v) ", uid, buglyRunVersion.Version, err)
|
||
}
|
||
|
||
defer func() {
|
||
// batch run 并且更新batch run表
|
||
batchStatus := model.BuglyBatchRunStatusDone
|
||
errMsg := ""
|
||
endTime := time.Now()
|
||
|
||
if err != nil {
|
||
batchStatus = model.BuglyBatchRunStatusFailed
|
||
errMsg = err.Error()
|
||
}
|
||
|
||
updateBuglyBatchRun := &model.BuglyBatchRun{
|
||
ID: buglyBatchRun.ID,
|
||
Status: batchStatus,
|
||
ErrorMsg: errMsg,
|
||
EndTime: endTime,
|
||
}
|
||
|
||
if err = s.dao.UpdateBuglyBatchRun(updateBuglyBatchRun); err != nil {
|
||
log.Error("runPerVersion UpdateBuglyBatchRun uid(%s) version(%s) err(%v) ", uid, buglyRunVersion.Version, err)
|
||
}
|
||
}()
|
||
})
|
||
|
||
break
|
||
}
|
||
}
|
||
|
||
rep = make(map[string]interface{})
|
||
rep["uid"] = uid
|
||
rep["enable_to_run"] = isEnableRun
|
||
|
||
if !isEnableRun {
|
||
err = ecode.MartheTaskInRunning
|
||
}
|
||
return
|
||
}
|
||
|
||
// BatchRunVersions Batch Run Versions
|
||
func (s *Service) BatchRunVersions() (err error) {
|
||
var (
|
||
buglyRunVersions []*model.BuglyVersion
|
||
uid = uuid.NewV4().String()
|
||
)
|
||
|
||
// 获取可以跑的版本号list
|
||
if buglyRunVersions, err = s.dao.FindEnableAndReadyVersions(); err != nil {
|
||
log.Error("GetBatchRunVersions err(%v) ", err)
|
||
return
|
||
}
|
||
|
||
for _, buglyRunVersion := range buglyRunVersions {
|
||
if _, err = s.RunVersions(buglyRunVersion.ID); err != nil {
|
||
log.Error("runPerVersion uid(%s) version(%s) err(%v) ", uid, buglyRunVersion.Version, err)
|
||
}
|
||
}
|
||
return
|
||
}
|
||
|
||
func (s *Service) runPerVersion(uid string, buglyRunVersion *model.BuglyVersion) (err error) {
|
||
var (
|
||
buglyRet *model.BugRet
|
||
buglyCookie *model.BuglyCookie
|
||
requestPageCnt int
|
||
c = context.Background()
|
||
lastRunTime time.Time
|
||
buglyBatchRun *model.BuglyBatchRun
|
||
buglyProject *model.BuglyProject
|
||
)
|
||
|
||
log.Info("start run version: [%s] batchId: [%s]", buglyRunVersion.Version, uid)
|
||
|
||
if buglyProject, err = s.dao.QueryBuglyProject(buglyRunVersion.BuglyProjectID); err != nil {
|
||
return
|
||
}
|
||
|
||
if buglyProject.ID == 0 {
|
||
err = ecode.NothingFound
|
||
return
|
||
}
|
||
|
||
//get issue total count
|
||
bugIssueRequest := &model.BugIssueRequest{
|
||
ProjectID: buglyProject.ProjectID,
|
||
PlatformID: buglyProject.PlatformID,
|
||
Version: buglyRunVersion.Version,
|
||
ExceptionType: buglyProject.ExceptionType,
|
||
StartNum: 0,
|
||
Rows: 1,
|
||
}
|
||
|
||
//get last run time
|
||
if buglyBatchRun, err = s.dao.QueryLastSuccessBatchRunByVersion(buglyRunVersion.Version); err != nil {
|
||
return
|
||
}
|
||
if buglyBatchRun.ID > 0 {
|
||
lastRunTime = buglyBatchRun.CTime
|
||
} else {
|
||
loc, _ := time.LoadLocation("Local")
|
||
if lastRunTime, err = time.ParseInLocation(model.TimeLayout, model.TimeLayout, loc); err != nil {
|
||
return
|
||
}
|
||
}
|
||
|
||
//get enable cookie
|
||
if buglyCookie, err = s.GetEnableCookie(); err != nil {
|
||
return
|
||
}
|
||
|
||
// if cookie, update cookie as expired
|
||
defer func() {
|
||
if err != nil && err == ecode.MartheCookieExpired {
|
||
s.DisableCookie(c, buglyCookie.ID)
|
||
}
|
||
}()
|
||
|
||
if buglyRet, err = s.dao.BuglyIssueAndRetry(c, buglyCookie, bugIssueRequest); err != nil || len(buglyRet.BugIssues) < 1 {
|
||
return
|
||
}
|
||
|
||
//获取issue count 和 page 上限
|
||
requestPageCnt = int(buglyRet.NumFound/s.c.Bugly.IssuePageSize) + 1
|
||
requestPageCntMax := s.c.Bugly.IssueCountUpper / s.c.Bugly.IssuePageSize
|
||
if requestPageCnt > requestPageCntMax {
|
||
requestPageCnt = requestPageCntMax
|
||
}
|
||
|
||
// update or add issue
|
||
for i := 0; i < requestPageCnt; i++ {
|
||
innerBreak := false
|
||
|
||
bugIssueRequest.StartNum = s.c.Bugly.IssuePageSize * i
|
||
bugIssueRequest.Rows = s.c.Bugly.IssuePageSize
|
||
|
||
var ret *model.BugRet
|
||
if ret, err = s.dao.BuglyIssueAndRetry(c, buglyCookie, bugIssueRequest); err != nil {
|
||
return
|
||
}
|
||
|
||
loc, _ := time.LoadLocation("Local")
|
||
issueLink := "/v2/crash-reporting/errors/%s/%s/report?pid=%s&searchType=detail&version=%s&start=0&date=all"
|
||
for _, issueDto := range ret.BugIssues {
|
||
var (
|
||
issueTime time.Time
|
||
bugIssueDetail *model.BugIssueDetail
|
||
tagStr string
|
||
bugDetail = "no detail"
|
||
)
|
||
|
||
tmpTime := []rune(issueDto.LastTime)
|
||
issueTime, _ = time.ParseInLocation(model.TimeLayout, string(tmpTime[:len(tmpTime)-4]), loc)
|
||
|
||
//issue时间早于库里面最新时间的,跳出
|
||
if issueTime.Before(lastRunTime) {
|
||
innerBreak = true
|
||
break
|
||
}
|
||
|
||
var tmpBuglyIssue *model.BuglyIssue
|
||
|
||
if tmpBuglyIssue, err = s.dao.GetBuglyIssue(issueDto.IssueID, issueDto.Version); err != nil {
|
||
log.Error("d.GetSaveIssues url(%s) err(%v)", "GetSaveIssues", err)
|
||
continue
|
||
}
|
||
|
||
for _, bugTag := range issueDto.Tags {
|
||
tagStr = tagStr + bugTag.TagName + ","
|
||
}
|
||
|
||
if tmpBuglyIssue.ID != 0 {
|
||
//update
|
||
issueRecord := &model.BuglyIssue{
|
||
IssueNo: issueDto.IssueID,
|
||
Title: issueDto.Title,
|
||
LastTime: issueTime,
|
||
HappenTimes: issueDto.Count,
|
||
UserTimes: issueDto.UserCount,
|
||
Version: issueDto.Version,
|
||
Tags: tagStr,
|
||
}
|
||
s.dao.UpdateBuglyIssue(issueRecord)
|
||
} else {
|
||
//create
|
||
if bugIssueDetail, err = s.dao.BuglyIssueDetailAndRetry(c, buglyCookie, buglyProject.ProjectID, buglyProject.PlatformID, issueDto.IssueID); err == nil {
|
||
bugDetail = bugIssueDetail.CallStack
|
||
}
|
||
|
||
issueURL := s.c.Bugly.Host + fmt.Sprintf(issueLink, buglyProject.ProjectID, issueDto.IssueID, buglyProject.PlatformID, buglyRunVersion.Version)
|
||
issueRecord := &model.BuglyIssue{
|
||
IssueNo: issueDto.IssueID,
|
||
Title: issueDto.Title,
|
||
LastTime: issueTime,
|
||
HappenTimes: issueDto.Count,
|
||
UserTimes: issueDto.UserCount,
|
||
Version: issueDto.Version,
|
||
Tags: tagStr,
|
||
Detail: bugDetail,
|
||
ExceptionMsg: issueDto.ExceptionMsg,
|
||
KeyStack: issueDto.KeyStack,
|
||
IssueLink: issueURL,
|
||
ProjectID: buglyProject.ProjectID,
|
||
}
|
||
s.dao.InsertBuglyIssue(issueRecord)
|
||
}
|
||
}
|
||
|
||
if innerBreak {
|
||
break
|
||
}
|
||
}
|
||
|
||
log.Info("end run version: [%s] batchId: [%s]", buglyRunVersion.Version, uid)
|
||
return
|
||
|
||
}
|
||
|
||
// GetBatchRunVersions Get Batch Run Versions.
|
||
func (s *Service) GetBatchRunVersions() (buglyRunVersions []*model.BuglyVersion, err error) {
|
||
var (
|
||
buglyVersions []*model.BuglyVersion
|
||
buglyBatchRuns []*model.BuglyBatchRun
|
||
)
|
||
if buglyVersions, err = s.dao.FindEnableAndReadyVersions(); err != nil {
|
||
return
|
||
}
|
||
|
||
if buglyBatchRuns, err = s.dao.QueryBuglyBatchRunsByStatus(model.BuglyBatchRunStatusRunning); err != nil {
|
||
return
|
||
}
|
||
|
||
// 排除正在执行的版本
|
||
for _, buglyVersion := range buglyVersions {
|
||
var isVersionRun bool
|
||
for _, buglyBatchRun := range buglyBatchRuns {
|
||
if buglyBatchRun.Version == buglyVersion.Version {
|
||
isVersionRun = true
|
||
break
|
||
}
|
||
}
|
||
|
||
if !isVersionRun {
|
||
buglyRunVersions = append(buglyRunVersions, buglyVersion)
|
||
}
|
||
}
|
||
return
|
||
}
|
||
|
||
// DisableBatchRunOverTime Disable Batch Run OverTime.
|
||
func (s *Service) DisableBatchRunOverTime() (err error) {
|
||
var (
|
||
buglyBatchRuns []*model.BuglyBatchRun
|
||
tapdBugRecords []*model.TapdBugRecord
|
||
timeNow = time.Now()
|
||
)
|
||
|
||
//清 未完成 disable batch run
|
||
if buglyBatchRuns, err = s.dao.QueryBuglyBatchRunsByStatus(model.BuglyBatchRunStatusRunning); err != nil {
|
||
return
|
||
}
|
||
|
||
for _, buglyBatchRun := range buglyBatchRuns {
|
||
if timeNow.Sub(buglyBatchRun.CTime).Hours() > float64(s.c.Scheduler.BatchRunOverHourTime) {
|
||
updateBuglyBatchRun := &model.BuglyBatchRun{
|
||
ID: buglyBatchRun.ID,
|
||
Status: model.BuglyBatchRunStatusFailed,
|
||
ErrorMsg: "over time",
|
||
EndTime: timeNow,
|
||
}
|
||
|
||
if err = s.dao.UpdateBuglyBatchRun(updateBuglyBatchRun); err != nil {
|
||
continue
|
||
}
|
||
}
|
||
}
|
||
|
||
// 清 未完成 disable insert tapd bug
|
||
if tapdBugRecords, err = s.dao.QueryTapdBugRecordByStatus(model.InsertBugStatusRunning); err != nil {
|
||
return
|
||
}
|
||
|
||
for _, tapdBugRecord := range tapdBugRecords {
|
||
if timeNow.Sub(tapdBugRecord.CTime).Hours() > float64(s.c.Scheduler.BatchRunOverHourTime) {
|
||
tapdBugRecord.Status = model.InsertBugStatusFailed
|
||
if err = s.dao.UpdateTapdBugRecord(tapdBugRecord); err != nil {
|
||
continue
|
||
}
|
||
}
|
||
}
|
||
|
||
return
|
||
}
|
||
|
||
func (s *Service) getBatchRunLock(buglyVersionId int64) (batchRunLock *sync.Mutex) {
|
||
s.syncBatchRunLock.Lock()
|
||
defer s.syncBatchRunLock.Unlock()
|
||
|
||
var ok bool
|
||
if batchRunLock, ok = s.mapBatchRunLocks[buglyVersionId]; !ok {
|
||
batchRunLock = new(sync.Mutex)
|
||
s.mapBatchRunLocks[buglyVersionId] = batchRunLock
|
||
}
|
||
return
|
||
}
|