Skip to content

Commit 3953d41

Browse files
authored
ui: use task state to determine if task is active (#14224)
The current implementation uses the task's finishedAt field to determine if a task is active of not, but this check is not accurate. A task in the "pending" state will not have finishedAt value but it's also not active. This discrepancy results in some components, like the inline stats chart of the task row component, to be displayed even whey they shouldn't.
1 parent dc1c50e commit 3953d41

File tree

6 files changed

+65
-23
lines changed

6 files changed

+65
-23
lines changed

.changelog/14224.txt

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
```release-note:bug
2+
ui: Fixed a bug that caused the allocation details page to display the stats bar chart even if the task was pending.
3+
```

ui/app/models/task-state.js

+6-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { computed } from '@ember/object';
2-
import { alias, none, and } from '@ember/object/computed';
2+
import { alias, and } from '@ember/object/computed';
33
import Fragment from 'ember-data-model-fragments/fragment';
44
import { attr } from '@ember-data/model';
55
import {
@@ -19,7 +19,6 @@ export default class TaskState extends Fragment {
1919
@attr('date') finishedAt;
2020
@attr('boolean') failed;
2121

22-
@none('finishedAt') isActive;
2322
@and('isActive', 'allocation.isRunning') isRunning;
2423

2524
@computed('task.kind')
@@ -58,6 +57,11 @@ export default class TaskState extends Fragment {
5857
return classMap[this.state] || 'is-dark';
5958
}
6059

60+
@computed('state')
61+
get isActive() {
62+
return this.state === 'running';
63+
}
64+
6165
restart() {
6266
return this.allocation.restart(this.name);
6367
}

ui/tests/acceptance/allocation-detail-test.js

+38-11
Original file line numberDiff line numberDiff line change
@@ -158,24 +158,47 @@ module('Acceptance | allocation detail', function (hooks) {
158158
});
159159

160160
test('each task row should list high-level information for the task', async function (assert) {
161-
const task = server.db.taskStates
162-
.where({ allocationId: allocation.id })
163-
.sortBy('name')[0];
164-
const events = server.db.taskEvents.where({ taskStateId: task.id });
165-
const event = events[events.length - 1];
161+
const job = server.create('job', {
162+
groupsCount: 1,
163+
groupTaskCount: 3,
164+
withGroupServices: true,
165+
createAllocations: false,
166+
});
167+
168+
const allocation = server.create('allocation', 'withTaskWithPorts', {
169+
clientStatus: 'running',
170+
jobId: job.id,
171+
});
166172

167173
const taskGroup = server.schema.taskGroups.where({
168174
jobId: allocation.jobId,
169175
name: allocation.taskGroup,
170176
}).models[0];
171177

172-
const jobTask = taskGroup.tasks.models.find((m) => m.name === task.name);
173-
const volumes = jobTask.volumeMounts.map((volume) => ({
174-
name: volume.Volume,
175-
source: taskGroup.volumes[volume.Volume].Source,
176-
}));
178+
// Set the expected task states.
179+
const states = ['running', 'pending', 'dead'];
180+
server.db.taskStates
181+
.where({ allocationId: allocation.id })
182+
.sortBy('name')
183+
.forEach((task, i) => {
184+
server.db.taskStates.update(task.id, { state: states[i] });
185+
});
186+
187+
await Allocation.visit({ id: allocation.id });
188+
189+
Allocation.tasks.forEach((taskRow, i) => {
190+
const task = server.db.taskStates
191+
.where({ allocationId: allocation.id })
192+
.sortBy('name')[i];
193+
const events = server.db.taskEvents.where({ taskStateId: task.id });
194+
const event = events[events.length - 1];
195+
196+
const jobTask = taskGroup.tasks.models.find((m) => m.name === task.name);
197+
const volumes = jobTask.volumeMounts.map((volume) => ({
198+
name: volume.Volume,
199+
source: taskGroup.volumes[volume.Volume].Source,
200+
}));
177201

178-
Allocation.tasks[0].as((taskRow) => {
179202
assert.equal(taskRow.name, task.name, 'Name');
180203
assert.equal(taskRow.state, task.state, 'State');
181204
assert.equal(taskRow.message, event.displayMessage, 'Event Message');
@@ -185,6 +208,10 @@ module('Acceptance | allocation detail', function (hooks) {
185208
'Event Time'
186209
);
187210

211+
const expectStats = task.state === 'running';
212+
assert.equal(taskRow.hasCpuMetrics, expectStats, 'CPU metrics');
213+
assert.equal(taskRow.hasMemoryMetrics, expectStats, 'Memory metrics');
214+
188215
const volumesText = taskRow.volumes;
189216
volumes.forEach((volume) => {
190217
assert.ok(

ui/tests/acceptance/exec-test.js

+12-10
Original file line numberDiff line numberDiff line change
@@ -27,11 +27,15 @@ module('Acceptance | exec', function (hooks) {
2727
});
2828

2929
this.job.taskGroups.models.forEach((taskGroup) => {
30-
server.create('allocation', {
30+
const alloc = server.create('allocation', {
3131
jobId: this.job.id,
3232
taskGroup: taskGroup.name,
3333
forceRunningClientStatus: true,
3434
});
35+
server.db.taskStates.update(
36+
{ allocationId: alloc.id },
37+
{ state: 'running' }
38+
);
3539
});
3640
});
3741

@@ -135,12 +139,11 @@ module('Acceptance | exec', function (hooks) {
135139

136140
let runningTaskGroup = this.job.taskGroups.models.sortBy('name')[1];
137141
runningTaskGroup.tasks.models.forEach((task, index) => {
142+
let state = 'running';
138143
if (index > 0) {
139-
this.server.db.taskStates.update(
140-
{ name: task.name },
141-
{ finishedAt: new Date() }
142-
);
144+
state = 'dead';
143145
}
146+
this.server.db.taskStates.update({ name: task.name }, { state });
144147
});
145148

146149
await Exec.visitJob({ job: this.job.id });
@@ -159,12 +162,11 @@ module('Acceptance | exec', function (hooks) {
159162
let runningTaskGroup = this.job.taskGroups.models.sortBy('name')[1];
160163
let changingTaskStateName;
161164
runningTaskGroup.tasks.models.sortBy('name').forEach((task, index) => {
165+
let state = 'running';
162166
if (index > 0) {
163-
this.server.db.taskStates.update(
164-
{ name: task.name },
165-
{ finishedAt: new Date() }
166-
);
167+
state = 'dead';
167168
}
169+
this.server.db.taskStates.update({ name: task.name }, { state });
168170

169171
if (index === 1) {
170172
changingTaskStateName = task.name;
@@ -187,7 +189,7 @@ module('Acceptance | exec', function (hooks) {
187189
);
188190

189191
if (changingTaskState) {
190-
changingTaskState.set('finishedAt', undefined);
192+
changingTaskState.set('state', 'running');
191193
}
192194
});
193195

ui/tests/acceptance/task-detail-test.js

+4
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,10 @@ module('Acceptance | task detail', function (hooks) {
2222
allocation = server.create('allocation', 'withTaskWithPorts', {
2323
clientStatus: 'running',
2424
});
25+
server.db.taskStates.update(
26+
{ allocationId: allocation.id },
27+
{ state: 'running' }
28+
);
2529
task = server.db.taskStates.where({ allocationId: allocation.id })[0];
2630

2731
await Task.visit({ id: allocation.id, name: task.name });

ui/tests/pages/allocations/detail.js

+2
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,8 @@ export default create({
5050
time: text('[data-test-time]'),
5151
volumes: text('[data-test-volumes]'),
5252

53+
hasCpuMetrics: isPresent('[data-test-cpu] .inline-chart progress'),
54+
hasMemoryMetrics: isPresent('[data-test-mem] .inline-chart progress'),
5355
hasUnhealthyDriver: isPresent('[data-test-icon="unhealthy-driver"]'),
5456
hasProxyTag: isPresent('[data-test-proxy-tag]'),
5557

0 commit comments

Comments
 (0)