Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(593)

Side by Side Diff: scheduler/appengine/ui/presentation.go

Issue 2945843002: scheduler WIP: add GetAllJobs api. (Closed)
Patch Set: meh Created 3 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « scheduler/appengine/presentation/state_test.go ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2015 The LUCI Authors. All rights reserved. 1 // Copyright 2015 The LUCI Authors. All rights reserved.
2 // Use of this source code is governed under the Apache License, Version 2.0 2 // Use of this source code is governed under the Apache License, Version 2.0
3 // that can be found in the LICENSE file. 3 // that can be found in the LICENSE file.
4 4
5 package ui 5 package ui
6 6
7 import ( 7 import (
8 "bytes" 8 "bytes"
9 "fmt" 9 "fmt"
10 "sort" 10 "sort"
11 "strings" 11 "strings"
12 "time" 12 "time"
13 13
14 "github.com/dustin/go-humanize" 14 "github.com/dustin/go-humanize"
15 "github.com/golang/protobuf/proto" 15 "github.com/golang/protobuf/proto"
16 "golang.org/x/net/context" 16 "golang.org/x/net/context"
17 17
18 "github.com/luci/luci-go/common/clock" 18 "github.com/luci/luci-go/common/clock"
19 "github.com/luci/luci-go/common/logging" 19 "github.com/luci/luci-go/common/logging"
20 20
21 "github.com/luci/luci-go/common/data/sortby" 21 "github.com/luci/luci-go/common/data/sortby"
22 "github.com/luci/luci-go/scheduler/appengine/catalog" 22 "github.com/luci/luci-go/scheduler/appengine/catalog"
23 "github.com/luci/luci-go/scheduler/appengine/engine" 23 "github.com/luci/luci-go/scheduler/appengine/engine"
24 "github.com/luci/luci-go/scheduler/appengine/messages" 24 "github.com/luci/luci-go/scheduler/appengine/messages"
25 "github.com/luci/luci-go/scheduler/appengine/presentation"
25 "github.com/luci/luci-go/scheduler/appengine/schedule" 26 "github.com/luci/luci-go/scheduler/appengine/schedule"
26 "github.com/luci/luci-go/scheduler/appengine/task" 27 "github.com/luci/luci-go/scheduler/appengine/task"
27 ) 28 )
28 29
29 // schedulerJob is UI representation of engine.Job entity. 30 // schedulerJob is UI representation of engine.Job entity.
30 type schedulerJob struct { 31 type schedulerJob struct {
31 ProjectID string 32 ProjectID string
32 JobID string 33 JobID string
33 Schedule string 34 Schedule string
34 Definition string 35 Definition string
35 Revision string 36 Revision string
36 RevisionURL string 37 RevisionURL string
37 State string 38 State string
38 Overruns int 39 Overruns int
39 NextRun string 40 NextRun string
40 Paused bool 41 Paused bool
41 LabelClass string 42 LabelClass string
42 JobFlavorIcon string 43 JobFlavorIcon string
43 JobFlavorTitle string 44 JobFlavorTitle string
44 45
45 sortGroup string // used only for sorting, doesn't show up in UI 46 sortGroup string // used only for sorting, doesn't show up in UI
46 now time.Time // as passed to makeJob 47 now time.Time // as passed to makeJob
47 traits task.Traits // as extracted from corresponding task.Manager 48 traits task.Traits // as extracted from corresponding task.Manager
48 } 49 }
49 50
50 var stateToLabelClass = map[engine.StateKind]string{ 51 var stateToLabelClass = map[presentation.PublicStateKind]string{
51 » engine.JobStateDisabled: "label-default", 52 » presentation.PublicStateRetrying: "label-danger",
52 » engine.JobStateScheduled: "label-primary", 53 » presentation.PublicStatePaused: "label-default",
53 » engine.JobStateSuspended: "label-default", 54 » presentation.PublicStateScheduled: "label-primary",
54 » engine.JobStateRunning: "label-info", 55 » presentation.PublicStateSuspended: "label-default",
55 » engine.JobStateOverrun: "label-warning", 56 » presentation.PublicStateRunning: "label-info",
57 » presentation.PublicStateOverrun: "label-warning",
58 » presentation.PublicStateWaiting: "label-warning",
59 » presentation.PublicStateStarting: "label-default",
56 } 60 }
57 61
58 var flavorToIconClass = []string{ 62 var flavorToIconClass = []string{
59 catalog.JobFlavorPeriodic: "glyphicon-time", 63 catalog.JobFlavorPeriodic: "glyphicon-time",
60 catalog.JobFlavorTriggered: "glyphicon-flash", 64 catalog.JobFlavorTriggered: "glyphicon-flash",
61 catalog.JobFlavorTrigger: "glyphicon-bell", 65 catalog.JobFlavorTrigger: "glyphicon-bell",
62 } 66 }
63 67
64 var flavorToTitle = []string{ 68 var flavorToTitle = []string{
65 catalog.JobFlavorPeriodic: "Periodic job", 69 catalog.JobFlavorPeriodic: "Periodic job",
66 catalog.JobFlavorTriggered: "Triggered job", 70 catalog.JobFlavorTriggered: "Triggered job",
67 catalog.JobFlavorTrigger: "Triggering job", 71 catalog.JobFlavorTrigger: "Triggering job",
68 } 72 }
69 73
70 // makeJob builds UI presentation for engine.Job. 74 // makeJob builds UI presentation for engine.Job.
71 func makeJob(c context.Context, j *engine.Job) *schedulerJob { 75 func makeJob(c context.Context, j *engine.Job) *schedulerJob {
72 » // Grab the task.Manager that's responsible for handling this job and 76 » traits, err := presentation.GetJobTraits(c, config(c).Catalog, j)
73 » // query if for the list of traits applying to this job.
74 » var manager task.Manager
75 » cat := config(c).Catalog
76 » taskDef, err := cat.UnmarshalTask(j.Task)
77 if err != nil { 77 if err != nil {
78 » » logging.WithError(err).Warningf(c, "Failed to unmarshal task pro to for %s", j.JobID) 78 » » logging.WithError(err).Warningf(c, "Failed to get task traits fo r %s", j.JobID)
79 » } else {
80 » » manager = cat.GetTaskManager(taskDef)
81 » }
82 » traits := task.Traits{}
83 » if manager != nil {
84 » » traits = manager.Traits()
85 } 79 }
86 80
87 now := clock.Now(c).UTC() 81 now := clock.Now(c).UTC()
88 nextRun := "" 82 nextRun := ""
89 switch ts := j.State.TickTime; { 83 switch ts := j.State.TickTime; {
90 case ts == schedule.DistantFuture: 84 case ts == schedule.DistantFuture:
91 nextRun = "-" 85 nextRun = "-"
92 case !ts.IsZero(): 86 case !ts.IsZero():
93 nextRun = humanize.RelTime(ts, now, "ago", "from now") 87 nextRun = humanize.RelTime(ts, now, "ago", "from now")
94 default: 88 default:
95 nextRun = "not scheduled yet" 89 nextRun = "not scheduled yet"
96 } 90 }
97 91
98 // Internal state names aren't very user friendly. Introduce some aliase s. 92 // Internal state names aren't very user friendly. Introduce some aliase s.
99 » state := "" 93 » state := presentation.GetPublicStateKind(j, traits)
100 » labelClass := "" 94 » labelClass := stateToLabelClass[state]
101 » switch { 95 » if j.State.State == engine.JobStateSlowQueue {
102 » case j.State.IsRetrying():
103 » » // Retries happen when invocation fails to launch (move from "ST ARTING" to
104 » » // "RUNNING" state). Such invocation is retried (as new invocati on). When
105 » » // a retry is enqueued, we display the job state as "RETRYING" ( even though
106 » » // technically it is still "QUEUED").
107 » » state = "RETRYING"
108 » » labelClass = "label-danger"
109 » case !traits.Multistage && j.State.InvocationID != 0:
110 » » // The job has an active invocation and the engine has called La unchTask for
111 » » // it already. Jobs with Multistage == false trait do all their work in
112 » » // LaunchTask, so we display them as "RUNNING" (instead of "STAR TING").
113 » » state = "RUNNING"
114 » » labelClass = "label-info"
115 » case j.State.State == engine.JobStateQueued:
116 » » // An invocation has been added to the task queue, and the engin e hasn't
117 » » // attempted to launch it yet.
118 » » state = "STARTING"
119 » » labelClass = "label-default"
120 » case j.State.State == engine.JobStateSlowQueue:
121 // Job invocation is still in the task queue, but new invocation should be 96 // Job invocation is still in the task queue, but new invocation should be
122 // starting now (so the queue is lagging for some reason). 97 // starting now (so the queue is lagging for some reason).
123 state = "STARTING"
124 labelClass = "label-warning" 98 labelClass = "label-warning"
125 case j.Paused && j.State.State == engine.JobStateSuspended:
126 // Paused jobs don't have a schedule, so they are always in "SUS PENDED"
127 // state. Make it clearer that they are just paused. This applie s to both
128 // triggered and periodic jobs.
129 state = "PAUSED"
130 labelClass = "label-default"
131 case j.State.State == engine.JobStateSuspended && j.Flavor == catalog.Jo bFlavorTriggered:
132 // Triggered jobs don't run on a schedule. They are in "SUSPENDE D" state
133 // between triggering events, rename it to "WAITING" for clarity .
134 state = "WAITING"
135 labelClass = "label-default"
136 default:
137 state = string(j.State.State)
138 labelClass = stateToLabelClass[j.State.State]
139 } 99 }
140
141 // Put triggers after regular jobs. 100 // Put triggers after regular jobs.
142 sortGroup := "A" 101 sortGroup := "A"
143 if j.Flavor == catalog.JobFlavorTrigger { 102 if j.Flavor == catalog.JobFlavorTrigger {
144 sortGroup = "B" 103 sortGroup = "B"
145 } 104 }
146 105
147 // JobID has form <project>/<id>. Split it into components. 106 // JobID has form <project>/<id>. Split it into components.
148 chunks := strings.Split(j.JobID, "/") 107 chunks := strings.Split(j.JobID, "/")
149 108
150 return &schedulerJob{ 109 return &schedulerJob{
151 ProjectID: chunks[0], 110 ProjectID: chunks[0],
152 JobID: chunks[1], 111 JobID: chunks[1],
153 Schedule: j.Schedule, 112 Schedule: j.Schedule,
154 Definition: taskToText(j.Task), 113 Definition: taskToText(j.Task),
155 Revision: j.Revision, 114 Revision: j.Revision,
156 RevisionURL: j.RevisionURL, 115 RevisionURL: j.RevisionURL,
157 » » State: state, 116 » » State: string(state),
158 Overruns: j.State.Overruns, 117 Overruns: j.State.Overruns,
159 NextRun: nextRun, 118 NextRun: nextRun,
160 Paused: j.Paused, 119 Paused: j.Paused,
161 LabelClass: labelClass, 120 LabelClass: labelClass,
162 JobFlavorIcon: flavorToIconClass[j.Flavor], 121 JobFlavorIcon: flavorToIconClass[j.Flavor],
163 JobFlavorTitle: flavorToTitle[j.Flavor], 122 JobFlavorTitle: flavorToTitle[j.Flavor],
164 123
165 sortGroup: sortGroup, 124 sortGroup: sortGroup,
166 now: now, 125 now: now,
167 traits: traits, 126 traits: traits,
(...skipping 114 matching lines...) Expand 10 before | Expand all | Expand 10 after
282 TriggeredBy: triggeredBy, 241 TriggeredBy: triggeredBy,
283 Started: humanize.RelTime(i.Started, j.now, "ago", "from now "), 242 Started: humanize.RelTime(i.Started, j.now, "ago", "from now "),
284 Duration: duration, 243 Duration: duration,
285 Status: string(status), 244 Status: string(status),
286 DebugLog: i.DebugLog, 245 DebugLog: i.DebugLog,
287 RowClass: statusToRowClass[status], 246 RowClass: statusToRowClass[status],
288 LabelClass: statusToLabelClass[status], 247 LabelClass: statusToLabelClass[status],
289 ViewURL: i.ViewURL, 248 ViewURL: i.ViewURL,
290 } 249 }
291 } 250 }
OLDNEW
« no previous file with comments | « scheduler/appengine/presentation/state_test.go ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698