Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add endTime into task execution summary #4326

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions cli/integration_tests/basic_monorepo/run_summary.t
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ Setup

$ cat $(/bin/ls .turbo/runs/*.json | head -n1) | jq '.tasks | map(select(.taskId == "my-app#build")) | .[0].execution'
{
"start": "[0-9-:\.TZ]+", (re)
"duration": [0-9]+, (re)
"startTime": [0-9]+, (re)
"endTime": [0-9]+, (re)
"status": "built",
"error": null
}
Expand All @@ -29,8 +29,8 @@ Setup

$ cat $(/bin/ls .turbo/runs/*.json | head -n1) | jq '.tasks | map(select(.taskId == "util#build")) | .[0].execution'
{
"start": "[0-9-:\.TZ]+", (re)
"duration": [0-9]+, (re)
"startTime": [0-9]+, (re)
"endTime": [0-9]+, (re)
"status": "built",
"error": null
}
Expand Down
73 changes: 44 additions & 29 deletions cli/internal/runsummary/execution_summary.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package runsummary

import (
"encoding/json"
"fmt"
"os"
"sync"
Expand Down Expand Up @@ -59,25 +60,35 @@ func (en executionEventName) toString() string {
// TaskExecutionSummary contains data about the state of a single task in a turbo run.
// Some fields are updated over time as the task prepares to execute and finishes execution.
type TaskExecutionSummary struct {
StartAt time.Time `json:"start"`

Duration time.Duration `json:"duration"`

// Target which has just changed
Label string `json:"-"`
startAt time.Time // set once
status executionEventName // current status, updated during execution
err error // only populated for failure statuses
duration time.Duration // updated during the task execution
}

// Its current status
Status string `json:"status"`
// MarshalJSON munges the TaskExecutionSummary into a format we want
// We'll use an anonmyous, private struct for this, so it's not confusingly duplicated
func (ts *TaskExecutionSummary) MarshalJSON() ([]byte, error) {
serializable := struct {
Start int64 `json:"startTime"`
End int64 `json:"endTime"`
Status string `json:"status"`
Err error `json:"error"`
}{
Start: ts.startAt.UnixMilli(),
End: ts.startAt.Add(ts.duration).UnixMilli(),
Status: ts.status.toString(),
Err: ts.err,
}

// Error, only populated for failure statuses
Err error `json:"error"`
return json.Marshal(&serializable)
}

// executionSummary is the state of the entire `turbo run`. Individual task state in `Tasks` field
type executionSummary struct {
// mu guards reads/writes to the `state` field
mu sync.Mutex `json:"-"`
state map[string]*TaskExecutionSummary `json:"-"` // key is a taskID
tasks map[string]*TaskExecutionSummary `json:"-"` // key is a taskID
Success int `json:"success"`
Failure int `json:"failed"`
Cached int `json:"cached"`
Expand All @@ -99,23 +110,23 @@ func newExecutionSummary(start time.Time, tracingProfile string) *executionSumma
Failure: 0,
Cached: 0,
Attempted: 0,
state: make(map[string]*TaskExecutionSummary),
tasks: make(map[string]*TaskExecutionSummary),
startedAt: start,
profileFilename: tracingProfile,
}
}

// Run starts the Execution of a single task. It returns a function that can
// be used to update the state of a given taskID with the executionEventName enum
func (es *executionSummary) run(label string) (func(outcome executionEventName, err error), *TaskExecutionSummary) {
func (es *executionSummary) run(taskID string) (func(outcome executionEventName, err error), *TaskExecutionSummary) {
start := time.Now()
taskExecutionSummary := es.add(&executionEvent{
Time: start,
Label: label,
Label: taskID,
Status: targetBuilding,
})

tracer := chrometracing.Event(label)
tracer := chrometracing.Event(taskID)

// This function can be called with an enum and an optional error to update
// the state of a given taskID.
Expand All @@ -125,11 +136,11 @@ func (es *executionSummary) run(label string) (func(outcome executionEventName,
result := &executionEvent{
Time: now,
Duration: now.Sub(start),
Label: label,
Label: taskID,
Status: outcome,
}
if err != nil {
result.Err = fmt.Errorf("running %v failed: %w", label, err)
result.Err = fmt.Errorf("running %v failed: %w", taskID, err)
}
// Ignore the return value here
es.add(result)
Expand All @@ -141,19 +152,23 @@ func (es *executionSummary) run(label string) (func(outcome executionEventName,
func (es *executionSummary) add(event *executionEvent) *TaskExecutionSummary {
es.mu.Lock()
defer es.mu.Unlock()
if s, ok := es.state[event.Label]; ok {
s.Status = event.Status.toString()
s.Err = event.Err
s.Duration = event.Duration

var taskExecSummary *TaskExecutionSummary
if ts, ok := es.tasks[event.Label]; ok {
// If we already know about this task, we'll update it with the new event
taskExecSummary = ts
} else {
es.state[event.Label] = &TaskExecutionSummary{
StartAt: event.Time,
Label: event.Label,
Status: event.Status.toString(),
Err: event.Err,
Duration: event.Duration,
}
// If we don't know about it yet, init and add it into the parent struct
// (event.Status should always be `targetBuilding` here.)
taskExecSummary = &TaskExecutionSummary{startAt: event.Time}
es.tasks[event.Label] = taskExecSummary
}

// Update the Status, Duration, and Err fields
taskExecSummary.status = event.Status
taskExecSummary.err = event.Err
taskExecSummary.duration = event.Duration

switch {
case event.Status == TargetBuildFailed:
es.Failure++
Expand All @@ -166,7 +181,7 @@ func (es *executionSummary) add(event *executionEvent) *TaskExecutionSummary {
es.Attempted++
}

return es.state[event.Label]
return es.tasks[event.Label]
}

// writeChromeTracing writes to a profile name if the `--profile` flag was passed to turbo run
Expand Down