mirror of
https://github.com/woodpecker-ci/woodpecker.git
synced 2024-06-18 05:10:48 +00:00
Fix pipeline timestamps (#730)
* only calculate time on running builds * Add updated timestamp into database and use it in frontend * add more trace logging * refactor (move grpc unrelated func into related package) * fix xorm schema * add todo
This commit is contained in:
parent
6af94d79e3
commit
2a5159f7fe
|
@ -321,6 +321,12 @@ func (s *RPC) Done(c context.Context, id string, state rpc.State) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
log.Trace().
|
||||||
|
Str("repo_id", fmt.Sprint(repo.ID)).
|
||||||
|
Str("build_id", fmt.Sprint(build.ID)).
|
||||||
|
Str("proc_id", id).
|
||||||
|
Msgf("gRPC Done with state: %#v", state)
|
||||||
|
|
||||||
if proc, err = shared.UpdateProcStatusToDone(s.store, *proc, state); err != nil {
|
if proc, err = shared.UpdateProcStatusToDone(s.store, *proc, state); err != nil {
|
||||||
log.Error().Msgf("error: done: cannot update proc_id %d state: %s", proc.ID, err)
|
log.Error().Msgf("error: done: cannot update proc_id %d state: %s", proc.ID, err)
|
||||||
}
|
}
|
||||||
|
@ -341,8 +347,8 @@ func (s *RPC) Done(c context.Context, id string, state rpc.State) error {
|
||||||
}
|
}
|
||||||
s.completeChildrenIfParentCompleted(procs, proc)
|
s.completeChildrenIfParentCompleted(procs, proc)
|
||||||
|
|
||||||
if !isThereRunningStage(procs) {
|
if !model.IsThereRunningStage(procs) {
|
||||||
if build, err = shared.UpdateStatusToDone(s.store, *build, buildStatus(procs), proc.Stopped); err != nil {
|
if build, err = shared.UpdateStatusToDone(s.store, *build, model.BuildStatus(procs), proc.Stopped); err != nil {
|
||||||
log.Error().Err(err).Msgf("error: done: cannot update build_id %d final state", build.ID)
|
log.Error().Err(err).Msgf("error: done: cannot update build_id %d final state", build.ID)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -361,23 +367,13 @@ func (s *RPC) Done(c context.Context, id string, state rpc.State) error {
|
||||||
s.buildCount.WithLabelValues(repo.FullName, build.Branch, string(build.Status), "total").Inc()
|
s.buildCount.WithLabelValues(repo.FullName, build.Branch, string(build.Status), "total").Inc()
|
||||||
s.buildTime.WithLabelValues(repo.FullName, build.Branch, string(build.Status), "total").Set(float64(build.Finished - build.Started))
|
s.buildTime.WithLabelValues(repo.FullName, build.Branch, string(build.Status), "total").Set(float64(build.Finished - build.Started))
|
||||||
}
|
}
|
||||||
if isMultiPipeline(procs) {
|
if model.IsMultiPipeline(procs) {
|
||||||
s.buildTime.WithLabelValues(repo.FullName, build.Branch, string(proc.State), proc.Name).Set(float64(proc.Stopped - proc.Started))
|
s.buildTime.WithLabelValues(repo.FullName, build.Branch, string(proc.State), proc.Name).Set(float64(proc.Stopped - proc.Started))
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func isMultiPipeline(procs []*model.Proc) bool {
|
|
||||||
countPPIDZero := 0
|
|
||||||
for _, proc := range procs {
|
|
||||||
if proc.PPID == 0 {
|
|
||||||
countPPIDZero++
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return countPPIDZero > 1
|
|
||||||
}
|
|
||||||
|
|
||||||
// Log implements the rpc.Log function
|
// Log implements the rpc.Log function
|
||||||
func (s *RPC) Log(c context.Context, id string, line *rpc.Line) error {
|
func (s *RPC) Log(c context.Context, id string, line *rpc.Line) error {
|
||||||
entry := new(logging.Entry)
|
entry := new(logging.Entry)
|
||||||
|
@ -398,31 +394,6 @@ func (s *RPC) completeChildrenIfParentCompleted(procs []*model.Proc, completedPr
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func isThereRunningStage(procs []*model.Proc) bool {
|
|
||||||
for _, p := range procs {
|
|
||||||
if p.PPID == 0 {
|
|
||||||
if p.Running() {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func buildStatus(procs []*model.Proc) model.StatusValue {
|
|
||||||
status := model.StatusSuccess
|
|
||||||
|
|
||||||
for _, p := range procs {
|
|
||||||
if p.PPID == 0 {
|
|
||||||
if p.Failing() {
|
|
||||||
status = p.State
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return status
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *RPC) updateRemoteStatus(ctx context.Context, repo *model.Repo, build *model.Build, proc *model.Proc) {
|
func (s *RPC) updateRemoteStatus(ctx context.Context, repo *model.Repo, build *model.Build, proc *model.Proc) {
|
||||||
user, err := s.store.GetUser(repo.UserID)
|
user, err := s.store.GetUser(repo.UserID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -28,6 +28,7 @@ type Build struct {
|
||||||
Error string `json:"error" xorm:"build_error"`
|
Error string `json:"error" xorm:"build_error"`
|
||||||
Enqueued int64 `json:"enqueued_at" xorm:"build_enqueued"`
|
Enqueued int64 `json:"enqueued_at" xorm:"build_enqueued"`
|
||||||
Created int64 `json:"created_at" xorm:"build_created"`
|
Created int64 `json:"created_at" xorm:"build_created"`
|
||||||
|
Updated int64 `json:"updated_at" xorm:"updated NOT NULL DEFAULT 0 'updated'"`
|
||||||
Started int64 `json:"started_at" xorm:"build_started"`
|
Started int64 `json:"started_at" xorm:"build_started"`
|
||||||
Finished int64 `json:"finished_at" xorm:"build_finished"`
|
Finished int64 `json:"finished_at" xorm:"build_finished"`
|
||||||
Deploy string `json:"deploy_to" xorm:"build_deploy"`
|
Deploy string `json:"deploy_to" xorm:"build_deploy"`
|
||||||
|
|
|
@ -68,6 +68,20 @@ func (p *Proc) IsParent() bool {
|
||||||
return p.PPID == 0
|
return p.PPID == 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// IsMultiPipeline checks if proc list contain more than one parent proc
|
||||||
|
func IsMultiPipeline(procs []*Proc) bool {
|
||||||
|
c := 0
|
||||||
|
for _, proc := range procs {
|
||||||
|
if proc.IsParent() {
|
||||||
|
c++
|
||||||
|
}
|
||||||
|
if c > 1 {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
// Tree creates a process tree from a flat process list.
|
// Tree creates a process tree from a flat process list.
|
||||||
func Tree(procs []*Proc) ([]*Proc, error) {
|
func Tree(procs []*Proc) ([]*Proc, error) {
|
||||||
var nodes []*Proc
|
var nodes []*Proc
|
||||||
|
@ -93,6 +107,32 @@ func Tree(procs []*Proc) ([]*Proc, error) {
|
||||||
return nodes, nil
|
return nodes, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// BuildStatus determine build status based on corresponding proc list
|
||||||
|
func BuildStatus(procs []*Proc) StatusValue {
|
||||||
|
status := StatusSuccess
|
||||||
|
|
||||||
|
for _, p := range procs {
|
||||||
|
if p.IsParent() && p.Failing() {
|
||||||
|
status = p.State
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return status
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsThereRunningStage determine if it contains procs running or pending to run
|
||||||
|
// TODO: return false based on depends_on (https://github.com/woodpecker-ci/woodpecker/pull/730#discussion_r795681697)
|
||||||
|
func IsThereRunningStage(procs []*Proc) bool {
|
||||||
|
for _, p := range procs {
|
||||||
|
if p.IsParent() {
|
||||||
|
if p.Running() {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
func findNode(nodes []*Proc, pid int) (*Proc, error) {
|
func findNode(nodes []*Proc, pid int) (*Proc, error) {
|
||||||
for _, node := range nodes {
|
for _, node := range nodes {
|
||||||
if node.PID == pid {
|
if node.PID == pid {
|
||||||
|
|
|
@ -40,13 +40,17 @@ export default (build: Ref<Build | undefined>) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
const start = build.value.started_at || 0;
|
const start = build.value.started_at || 0;
|
||||||
const end = build.value.finished_at || 0;
|
const end = build.value.finished_at || build.value.updated_at || 0;
|
||||||
|
|
||||||
if (start === 0) {
|
if (start === 0) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (end === 0) {
|
if (end === 0) {
|
||||||
|
// only calculate time on running builds
|
||||||
|
if (build.value.status !== 'running') {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
return Date.now() - start * 1000;
|
return Date.now() - start * 1000;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -18,6 +18,9 @@ export type Build = {
|
||||||
// When the build request was received.
|
// When the build request was received.
|
||||||
created_at: number;
|
created_at: number;
|
||||||
|
|
||||||
|
// When the build was updated last time in database.
|
||||||
|
updated_at: number;
|
||||||
|
|
||||||
// When the build was enqueued.
|
// When the build was enqueued.
|
||||||
enqueued_at: number;
|
enqueued_at: number;
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue