123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485 |
- package service
- import (
- "context"
- "encoding/json"
- "fmt"
- "time"
- "go-common/app/admin/ep/saga/model"
- "go-common/app/admin/ep/saga/service/utils"
- "go-common/library/cache/redis"
- "go-common/library/log"
- "github.com/xanzy/go-gitlab"
- )
- // QueryProjectJob ...
- func (s *Service) QueryProjectJob(c context.Context, req *model.ProjectJobRequest) (resp *model.ProjectJobResp, err error) {
- var (
- layout = "2006-01-02"
- queryCacheKey string
- jobs []*model.ProjectJob
- since time.Time
- util time.Time
- )
- resp = &model.ProjectJobResp{ProjectID: req.ProjectID, QueryDescription: "最近一月的Jobs日常", State: req.Scope, DataInfo: []*model.DateJobInfo{}}
- year, month, day := time.Now().Date()
- util = time.Date(year, month, day-1, 0, 0, 0, 0, time.Local)
- since = util.AddDate(0, -1, 0)
- //query from redis first
- queryCacheKey = fmt.Sprintf("saga_admin_job_%d_%s_%s_%s_%d", req.ProjectID, req.Branch, req.Scope, req.Machine, req.StatisticsType)
- if err = s.dao.ItemRedis(c, queryCacheKey, &resp); err != redis.ErrNil {
- return
- }
- if resp.TotalItem, jobs, err = s.queryProjectJobByTime(c, req.ProjectID, since, util); err != nil {
- return
- }
- //init map key
- pendingTime := make(map[string][]float64)
- runningTime := make(map[string][]float64)
- for i := 1; ; i++ {
- day := since.AddDate(0, 0, i)
- if day.After(util) {
- break
- }
- dayStr := day.Format(layout)
- pendingTime[dayStr] = []float64{}
- runningTime[dayStr] = []float64{}
- resp.DataInfo = append(resp.DataInfo, &model.DateJobInfo{Date: dayStr, SlowestPendingJob: []*model.ProjectJob{}})
- }
- //根据查询条件进行过滤
- newJobs := jobs[:0]
- if req.Branch != "" {
- for _, job := range jobs {
- if job.Branch == req.Branch {
- newJobs = append(newJobs, job)
- }
- }
- jobs = newJobs
- newJobs = jobs[:0]
- }
- if req.User != "" {
- for _, job := range jobs {
- if job.User == req.User {
- newJobs = append(newJobs, job)
- }
- }
- jobs = newJobs
- newJobs = jobs[:0]
- }
- if req.Machine != "" {
- for _, job := range jobs {
- if job.Machine == req.Machine {
- newJobs = append(newJobs, job)
- }
- }
- jobs = newJobs
- }
- //统计pending running 时间
- for _, job := range jobs {
- var (
- jobInfo *model.DateJobInfo
- )
- jobDate := job.CreatedAt.Format(layout)
- for _, j := range resp.DataInfo {
- if j.Date == jobDate {
- jobInfo = j
- break
- }
- }
- jobInfo.JobTotal++
- if job.Status == req.Scope {
- jobInfo.StatusNum++
- if job.StartedAt != nil && job.CreatedAt != nil {
- pending := job.StartedAt.Sub(*job.CreatedAt).Seconds()
- pendingTime[jobDate] = append(pendingTime[jobDate], pending)
- if pending >= 300 {
- jobInfo.SlowestPendingJob = append(jobInfo.SlowestPendingJob, job)
- }
- }
- if job.Status == "success" {
- running := job.FinishedAt.Sub(*job.StartedAt).Seconds()
- runningTime[jobDate] = append(runningTime[jobDate], running)
- }
- }
- }
- for k, v := range runningTime {
- var (
- jobInfo *model.DateJobInfo
- )
- for _, j := range resp.DataInfo {
- if j.Date == k {
- jobInfo = j
- break
- }
- }
- jobInfo.PendingTime = utils.CalAverageTime(req.StatisticsType, v)
- jobInfo.RunningTime = utils.CalAverageTime(req.StatisticsType, pendingTime[k])
- }
- // set data to redis
- err = s.dao.SetItemRedis(c, queryCacheKey, resp, model.ExpiredOneDay)
- return
- }
- // queryProjectJobByTime ...
- func (s *Service) queryProjectJobByTime(c context.Context, projectID int, since, util time.Time) (count int, result []*model.ProjectJob, err error) {
- var (
- resp *gitlab.Response
- jobs []gitlab.Job
- overTime bool
- )
- if _, resp, err = s.gitlab.ListProjectJobs(projectID, 1); err != nil {
- return
- }
- if resp.TotalItems <= 0 {
- return
- }
- for page := 1; ; page++ {
- if jobs, resp, err = s.gitlab.ListProjectJobs(projectID, page); err != nil {
- return
- }
- for _, job := range jobs {
- if job.CreatedAt == nil {
- continue
- }
- if job.CreatedAt.After(since) && job.CreatedAt.Before(util) {
- count++
- jobInfo := &model.ProjectJob{
- Status: job.Status,
- Branch: job.Ref,
- Machine: job.Runner.Description,
- User: job.User.Name,
- CreatedAt: job.CreatedAt,
- StartedAt: job.StartedAt,
- FinishedAt: job.FinishedAt}
- result = append(result, jobInfo)
- }
- if job.CreatedAt.Before(since) {
- overTime = true
- }
- }
- if overTime {
- break
- }
- if resp.NextPage == 0 {
- break
- }
- }
- return
- }
- // QueryProjectJobNew ...
- func (s *Service) QueryProjectJobNew(c context.Context, req *model.ProjectJobRequest) (resp *model.ProjectJobResp, err error) {
- var (
- layout = "2006-01-02"
- fmtLayout = `%d-%d-%d 00:00:00`
- jobs []*model.StatisticsJobs
- )
- resp = &model.ProjectJobResp{ProjectID: req.ProjectID, QueryDescription: "最近一月的Jobs日常", State: req.Scope, DataInfo: []*model.DateJobInfo{}}
- year, month, day := time.Now().Date()
- until := time.Date(year, month, day-1, 0, 0, 0, 0, time.Local)
- since := until.AddDate(0, -1, 0)
- sinceStr := fmt.Sprintf(fmtLayout, since.Year(), since.Month(), since.Day())
- untilStr := fmt.Sprintf(fmtLayout, until.Year(), until.Month(), until.Day())
- if resp.TotalItem, jobs, err = s.dao.QueryJobsByTime(req.ProjectID, req, sinceStr, untilStr); err != nil {
- return
- }
- //init map key
- pendingTime := make(map[string][]float64)
- runningTime := make(map[string][]float64)
- for i := 1; ; i++ {
- day := since.AddDate(0, 0, i)
- if day.After(until) {
- break
- }
- dayStr := day.Format(layout)
- pendingTime[dayStr] = []float64{}
- runningTime[dayStr] = []float64{}
- resp.DataInfo = append(resp.DataInfo, &model.DateJobInfo{Date: dayStr, SlowestPendingJob: []*model.ProjectJob{}})
- }
- //统计pending running 时间
- for _, job := range jobs {
- var (
- jobInfo *model.DateJobInfo
- )
- jobDate := job.CreatedAt.Format(layout)
- for _, j := range resp.DataInfo {
- if j.Date == jobDate {
- jobInfo = j
- break
- }
- }
- if jobInfo == nil {
- continue
- }
- jobInfo.JobTotal++
- if job.Status == req.Scope {
- jobInfo.StatusNum++
- if job.StartedAt != nil && job.CreatedAt != nil {
- pending := job.StartedAt.Sub(*job.CreatedAt).Seconds()
- pendingTime[jobDate] = append(pendingTime[jobDate], pending)
- if pending >= 300 {
- jo := &model.ProjectJob{
- Status: job.Status,
- User: job.UserName,
- Branch: job.Ref,
- Machine: job.RunnerDescription,
- CreatedAt: job.CreatedAt,
- StartedAt: job.StartedAt,
- FinishedAt: job.FinishedAt,
- }
- jobInfo.SlowestPendingJob = append(jobInfo.SlowestPendingJob, jo)
- }
- }
- if job.Status == "success" {
- running := job.FinishedAt.Sub(*job.StartedAt).Seconds()
- runningTime[jobDate] = append(runningTime[jobDate], running)
- }
- }
- }
- for k, v := range runningTime {
- var (
- jobInfo *model.DateJobInfo
- )
- for _, j := range resp.DataInfo {
- if j.Date == k {
- jobInfo = j
- break
- }
- }
- jobInfo.PendingTime = utils.CalAverageTime(req.StatisticsType, v)
- jobInfo.RunningTime = utils.CalAverageTime(req.StatisticsType, pendingTime[k])
- }
- return
- }
- /*-------------------------------------- sync job ----------------------------------------*/
- // SyncProjectJobs ...
- func (s *Service) SyncProjectJobs(projectID int) (result *model.SyncResult, err error) {
- var (
- //syncAllTime = conf.Conf.Property.SyncData.SyncAllTime
- syncAllTime = false
- since *time.Time
- until *time.Time
- projectInfo *model.ProjectInfo
- )
- if projectInfo, err = s.dao.ProjectInfoByID(projectID); err != nil {
- return
- }
- if !syncAllTime {
- since, until = utils.CalSyncTime()
- log.Info("sync project(%d) job time since: %v, until: %v", projectID, since, until)
- if result, err = s.SyncProjectJobsByTime(projectID, projectInfo.Name, *since, *until); err != nil {
- return
- }
- } else {
- if result, err = s.SyncProjectJobsNormal(projectID, projectInfo.Name); err != nil {
- return
- }
- }
- return
- }
- // SyncProjectJobsNormal ...
- func (s *Service) SyncProjectJobsNormal(projectID int, projectName string) (result *model.SyncResult, err error) {
- var (
- jobs []gitlab.Job
- resp *gitlab.Response
- )
- result = &model.SyncResult{}
- for page := 1; ; page++ {
- result.TotalPage++
- if jobs, resp, err = s.gitlab.ListProjectJobs(projectID, page); err != nil {
- return
- }
- for _, job := range jobs {
- if err = s.structureDatabasejob(projectID, projectName, job); err != nil {
- log.Error("job Save Database err: projectID(%d), JobID(%d)", projectID, job.ID)
- err = nil
- errData := &model.FailData{
- ChildID: job.ID,
- }
- result.FailData = append(result.FailData, errData)
- continue
- }
- result.TotalNum++
- }
- if resp.NextPage == 0 {
- break
- }
- }
- return
- }
- // SyncProjectJobsByTime ...
- func (s *Service) SyncProjectJobsByTime(projectID int, projectName string, since, until time.Time) (result *model.SyncResult, err error) {
- var (
- jobs []gitlab.Job
- resp *gitlab.Response
- startQuery bool
- )
- result = &model.SyncResult{}
- if _, resp, err = s.gitlab.ListProjectJobs(projectID, 1); err != nil {
- return
- }
- page := 1
- for page <= resp.TotalPages {
- result.TotalPage++
- if !startQuery {
- if jobs, _, err = s.gitlab.ListProjectJobs(projectID, page); err != nil {
- return
- }
- if page == 1 && len(jobs) <= 0 {
- return
- }
- if jobs[0].CreatedAt.After(until) {
- page++
- continue
- } else {
- startQuery = true
- page--
- continue
- }
- }
- if jobs, _, err = s.gitlab.ListProjectJobs(projectID, page); err != nil {
- return
- }
- for _, job := range jobs {
- createTime := job.CreatedAt
- if createTime.After(since) && createTime.Before(until) {
- if err = s.structureDatabasejob(projectID, projectName, job); err != nil {
- log.Error("job Save Database err: projectID(%d), JobID(%d)", projectID, job.ID)
- err = nil
- errData := &model.FailData{
- ChildID: job.ID,
- }
- result.FailData = append(result.FailData, errData)
- continue
- }
- result.TotalNum++
- }
- if createTime.Before(since) {
- return
- }
- }
- page++
- }
- return
- }
- // structureDatabasejob ...
- func (s *Service) structureDatabasejob(projectID int, projectName string, job gitlab.Job) (err error) {
- var (
- jobArtifactsFile string
- jobCommitID string
- )
- jobArtifactsFileByte, _ := json.Marshal(job.ArtifactsFile)
- jobArtifactsFile = string(jobArtifactsFileByte)
- if job.Commit != nil {
- jobCommitID = job.Commit.ID
- }
- jobDB := &model.StatisticsJobs{
- ProjectID: projectID,
- ProjectName: projectName,
- CommitID: jobCommitID,
- CreatedAt: job.CreatedAt,
- Coverage: job.Coverage,
- ArtifactsFile: jobArtifactsFile,
- FinishedAt: job.FinishedAt,
- JobID: job.ID,
- Name: job.Name,
- Ref: job.Ref,
- RunnerID: job.Runner.ID,
- RunnerDescription: job.Runner.Description,
- Stage: job.Stage,
- StartedAt: job.StartedAt,
- Status: job.Status,
- Tag: job.Tag,
- UserID: job.User.ID,
- UserName: job.User.Name,
- WebURL: job.WebURL,
- }
- return s.SaveDatabasejob(jobDB)
- }
- // SaveDatabasejob ...
- func (s *Service) SaveDatabasejob(jobDB *model.StatisticsJobs) (err error) {
- var total int
- if total, err = s.dao.HasJob(jobDB.ProjectID, jobDB.JobID); err != nil {
- log.Error("SaveDatabaseJob HasJob(%+v)", err)
- return
- }
- // found only one, so update
- if total == 1 {
- if err = s.dao.UpdateJob(jobDB.ProjectID, jobDB.JobID, jobDB); err != nil {
- log.Error("SaveDatabaseJob UpdateJob(%+v)", err)
- return
- }
- return
- } else if total > 1 {
- // found repeated row, this situation will not exist under normal
- log.Warn("SaveDatabasejob job has more rows(%d)", total)
- return
- }
- // insert row now
- if err = s.dao.CreateJob(jobDB); err != nil {
- log.Error("SaveDatabaseJob CreateJob(%+v)", err)
- return
- }
- return
- }
|