You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
358 lines
9.4 KiB
358 lines
9.4 KiB
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 |
|
}
|
|
|