Skip to content

Commit ee3ac42

Browse files
authored
✨ [Frontend] Listen to the serviceStatus websocket event (#6487)
1 parent 3c85620 commit ee3ac42

File tree

10 files changed

+109
-94
lines changed

10 files changed

+109
-94
lines changed

packages/models-library/src/models_library/api_schemas_dynamic_sidecar/ports.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,14 @@ class OutputStatus(StrAutoEnum):
1111
UPLOAD_STARTED = auto()
1212
UPLOAD_WAS_ABORTED = auto()
1313
UPLOAD_FINISHED_SUCCESSFULLY = auto()
14-
UPLOAD_FINISHED_WITH_ERRROR = auto()
14+
UPLOAD_FINISHED_WITH_ERROR = auto()
1515

1616

1717
class InputStatus(StrAutoEnum):
1818
DOWNLOAD_STARTED = auto()
1919
DOWNLOAD_WAS_ABORTED = auto()
2020
DOWNLOAD_FINISHED_SUCCESSFULLY = auto()
21-
DOWNLOAD_FINISHED_WITH_ERRROR = auto()
21+
DOWNLOAD_FINISHED_WITH_ERROR = auto()
2222

2323

2424
class _PortStatusCommon(BaseModel):

services/dynamic-sidecar/src/simcore_service_dynamic_sidecar/modules/notifications/_notifications_ports.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ async def send_output_port_upload_finished_with_error(
5252
self, port_key: ServicePortKey
5353
) -> None:
5454
await self._send_output_port_status(
55-
port_key, OutputStatus.UPLOAD_FINISHED_WITH_ERRROR
55+
port_key, OutputStatus.UPLOAD_FINISHED_WITH_ERROR
5656
)
5757

5858
async def send_input_port_download_started(self, port_key: ServicePortKey) -> None:
@@ -74,5 +74,5 @@ async def send_input_port_download_finished_with_error(
7474
self, port_key: ServicePortKey
7575
) -> None:
7676
await self._send_input_port_status(
77-
port_key, InputStatus.DOWNLOAD_FINISHED_WITH_ERRROR
77+
port_key, InputStatus.DOWNLOAD_FINISHED_WITH_ERROR
7878
)

services/dynamic-sidecar/tests/unit/test_modules_notifier.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -289,7 +289,7 @@ async def test_notifier_send_input_port_status(
289289
await port_notifier.send_input_port_download_finished_succesfully(
290290
port_key
291291
)
292-
case InputStatus.DOWNLOAD_FINISHED_WITH_ERRROR:
292+
case InputStatus.DOWNLOAD_FINISHED_WITH_ERROR:
293293
await port_notifier.send_input_port_download_finished_with_error(
294294
port_key
295295
)
@@ -378,7 +378,7 @@ async def test_notifier_send_output_port_status(
378378
await port_notifier.send_output_port_upload_finished_successfully(
379379
port_key
380380
)
381-
case OutputStatus.UPLOAD_FINISHED_WITH_ERRROR:
381+
case OutputStatus.UPLOAD_FINISHED_WITH_ERROR:
382382
await port_notifier.send_output_port_upload_finished_with_error(
383383
port_key
384384
)

services/static-webserver/client/source/class/osparc/dashboard/Dashboard.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,8 @@ qx.Class.define("osparc.dashboard.Dashboard", {
138138
});
139139
const tabButton = tabPage.getChildControl("button");
140140
tabButton.set({
141-
minWidth: 50
141+
minWidth: 50,
142+
maxHeight: 36,
142143
});
143144
tabButton.ttt = label;
144145
tabButton.getChildControl("label").set({

services/static-webserver/client/source/class/osparc/data/model/IframeHandler.js

Lines changed: 73 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,12 @@ qx.Class.define("osparc.data.model.IframeHandler", {
2323
this.setStudy(study);
2424
this.setNode(node);
2525

26+
node.getStatus().addListener("changeInteractive", e => {
27+
const newStatus = e.getData();
28+
const oldStatus = e.getOldData();
29+
this.__statusInteractiveChanged(newStatus, oldStatus);
30+
});
31+
2632
this.__initLoadingPage();
2733
this.__initIFrame();
2834
},
@@ -51,12 +57,6 @@ qx.Class.define("osparc.data.model.IframeHandler", {
5157
check: "osparc.widget.PersistentIframe",
5258
init: null,
5359
nullable: true
54-
},
55-
56-
polling: {
57-
check: "Boolean",
58-
init: null,
59-
nullable: true
6060
}
6161
},
6262

@@ -69,12 +69,7 @@ qx.Class.define("osparc.data.model.IframeHandler", {
6969
__stopRequestingStatus: null,
7070
__retriesLeft: null,
7171

72-
startPolling: function() {
73-
if (this.isPolling()) {
74-
return;
75-
}
76-
this.setPolling(true);
77-
72+
checkState: function() {
7873
this.getNode().getStatus().getProgressSequence()
7974
.resetSequence();
8075

@@ -87,7 +82,7 @@ qx.Class.define("osparc.data.model.IframeHandler", {
8782
.resetSequence();
8883

8984
this.__unresponsiveRetries = 5;
90-
this.__nodeState(false);
85+
this.__nodeState();
9186

9287
this.getIFrame().resetSource();
9388
},
@@ -124,47 +119,27 @@ qx.Class.define("osparc.data.model.IframeHandler", {
124119
});
125120
loadingPage.addExtraWidget(sequenceWidget);
126121

127-
nodeStatus.addListener("changeInteractive", () => {
128-
loadingPage.setHeader(this.__getLoadingPageHeader());
129-
const status = nodeStatus.getInteractive();
130-
if (["idle", "failed"].includes(status)) {
131-
const startButton = new qx.ui.form.Button().set({
132-
label: this.tr("Start"),
133-
icon: "@FontAwesome5Solid/play/18",
134-
font: "text-18",
135-
allowGrowX: false,
136-
height: 32
137-
});
138-
startButton.addListener("execute", () => node.requestStartNode());
139-
loadingPage.addWidgetToMessages(startButton);
140-
} else {
141-
loadingPage.setMessages([]);
142-
}
143-
}, this);
144122
this.setLoadingPage(loadingPage);
145123
},
146124

147-
__getLoadingPageHeader: function() {
125+
__getLoadingPageHeader: function(status) {
148126
const node = this.getNode();
149-
let statusText = this.tr("Starting");
150-
const status = node.getStatus().getInteractive();
151-
if (status) {
152-
statusText = status.charAt(0).toUpperCase() + status.slice(1);
127+
if (status === undefined) {
128+
status = node.getStatus().getInteractive();
153129
}
130+
const statusText = status ? (status.charAt(0).toUpperCase() + status.slice(1)) : this.tr("Starting");
154131
const metadata = node.getMetaData();
155132
const versionDisplay = osparc.service.Utils.extractVersionDisplay(metadata);
156133
return statusText + " " + node.getLabel() + " <span style='font-size: 16px;font-weight: normal;'><sub>v" + versionDisplay + "</sub></span>";
157134
},
158135

159-
__nodeState: function(starting=true) {
136+
__nodeState: function() {
160137
// Check if study is still there
161138
if (this.getStudy() === null || this.__stopRequestingStatus === true) {
162-
this.setPolling(false);
163139
return;
164140
}
165141
// Check if node is still there
166142
if (this.getStudy().getWorkbench().getNode(this.getNode().getNodeId()) === null) {
167-
this.setPolling(false);
168143
return;
169144
}
170145

@@ -176,7 +151,7 @@ qx.Class.define("osparc.data.model.IframeHandler", {
176151
}
177152
};
178153
osparc.data.Resources.fetch("studies", "getNode", params)
179-
.then(data => this.__onNodeState(data, starting))
154+
.then(data => this.onNodeState(data))
180155
.catch(err => {
181156
let errorMsg = `Error retrieving ${node.getLabel()} status: ${err}`;
182157
if ("status" in err && err.status === 406) {
@@ -191,7 +166,6 @@ qx.Class.define("osparc.data.model.IframeHandler", {
191166
};
192167
node.fireDataEvent("showInLogger", errorMsgData);
193168
if ("status" in err && err.status === 406) {
194-
this.setPolling(false);
195169
return;
196170
}
197171
if (this.__unresponsiveRetries > 0) {
@@ -203,32 +177,24 @@ qx.Class.define("osparc.data.model.IframeHandler", {
203177
};
204178
node.fireDataEvent("showInLogger", retryMsgData);
205179
this.__unresponsiveRetries--;
206-
const interval = Math.floor(Math.random() * 5000) + 3000;
207-
setTimeout(() => this.__nodeState(), interval);
208180
} else {
209-
this.setPolling(false);
210181
node.getStatus().setInteractive("failed");
211182
osparc.FlashMessenger.getInstance().logAs(this.tr("There was an error starting") + " " + node.getLabel(), "ERROR");
212183
}
213184
});
214185
},
215186

216-
__onNodeState: function(data, starting=true) {
187+
onNodeState: function(data) {
217188
const serviceState = data["service_state"];
218189
const nodeId = data["service_uuid"];
219190
const node = this.getNode();
220191
const status = node.getStatus();
221-
let nextPollIn = null;
222-
let pollingInNextStage = null;
223192
switch (serviceState) {
224193
case "idle": {
225194
status.setInteractive(serviceState);
226-
if (starting && this.__unresponsiveRetries>0) {
195+
if (this.__unresponsiveRetries>0) {
227196
// a bit of a hack. We will get rid of it when the backend pushes the states
228197
this.__unresponsiveRetries--;
229-
nextPollIn = 2000;
230-
} else {
231-
this.setPolling(false);
232198
}
233199
break;
234200
}
@@ -248,36 +214,32 @@ qx.Class.define("osparc.data.model.IframeHandler", {
248214
node.fireDataEvent("showInLogger", msgData);
249215
}
250216
status.setInteractive(serviceState);
251-
nextPollIn = 10000;
252217
break;
253218
}
254219
case "stopping":
255220
case "unknown":
256221
case "starting":
257222
case "pulling": {
258223
status.setInteractive(serviceState);
259-
nextPollIn = 5000;
260224
break;
261225
}
262226
case "running": {
263227
if (nodeId !== node.getNodeId()) {
264228
break;
265229
}
266-
if (!starting) {
267-
status.setInteractive("stopping");
268-
nextPollIn = 5000;
269-
break;
270-
}
271230
const {
272231
srvUrl,
273232
isDynamicV2
274233
} = osparc.utils.Utils.computeServiceUrl(data);
275234
node.setDynamicV2(isDynamicV2);
276-
if (srvUrl) {
235+
if (
236+
srvUrl &&
237+
srvUrl !== node.getServiceUrl() // if it's already connected, do not restart the connection process
238+
) {
239+
this.__statusInteractiveChanged("connecting", node.getStatus().getInteractive());
277240
this.__retriesLeft = 40;
278241
this.__waitForServiceReady(srvUrl);
279242
}
280-
pollingInNextStage = true;
281243
break;
282244
}
283245
case "complete":
@@ -297,18 +259,10 @@ qx.Class.define("osparc.data.model.IframeHandler", {
297259
console.error(serviceState, "service state not supported");
298260
break;
299261
}
300-
if (nextPollIn) {
301-
qx.event.Timer.once(() => this.__nodeState(starting), this, nextPollIn);
302-
} else if (pollingInNextStage !== true) {
303-
this.setPolling(false);
304-
}
305262
},
306263

307264
__waitForServiceReady: function(srvUrl) {
308-
this.getNode().getStatus().setInteractive("connecting");
309-
310265
if (this.__retriesLeft === 0) {
311-
this.setPolling(false);
312266
return;
313267
}
314268

@@ -317,7 +271,6 @@ qx.Class.define("osparc.data.model.IframeHandler", {
317271

318272
// Check if node is still there
319273
if (this.getStudy().getWorkbench().getNode(this.getNode().getNodeId()) === null) {
320-
this.setPolling(false);
321274
return;
322275
}
323276
const interval = 5000;
@@ -335,7 +288,6 @@ qx.Class.define("osparc.data.model.IframeHandler", {
335288
console.log("Connecting: fetch's response status", response.status);
336289
}
337290
if (response.status < 400) {
338-
this.setPolling(false);
339291
this.__serviceReadyIn(srvUrl);
340292
} else {
341293
console.log(`Connecting: ${srvUrl} is not reachable. Status: ${response.status}`);
@@ -356,16 +308,57 @@ qx.Class.define("osparc.data.model.IframeHandler", {
356308
const node = this.getNode();
357309
node.setServiceUrl(srvUrl);
358310
node.getStatus().setInteractive("ready");
359-
const msg = "Service ready on " + srvUrl;
360-
const msgData = {
361-
nodeId: node.getNodeId(),
362-
msg,
363-
level: "INFO"
364-
};
365-
node.fireDataEvent("showInLogger", msgData);
366-
this.__restartIFrame();
367-
if (!node.isDynamicV2()) {
368-
node.callRetrieveInputs();
311+
},
312+
313+
__statusInteractiveChanged: function(status, oldStatus) {
314+
if (status === oldStatus) {
315+
return;
316+
}
317+
318+
const node = this.getNode();
319+
320+
const loadingPage = node.getLoadingPage();
321+
loadingPage.setHeader(this.__getLoadingPageHeader(status));
322+
loadingPage.clearMessages();
323+
if (["idle", "failed"].includes(status)) {
324+
const startButton = new qx.ui.form.Button().set({
325+
label: this.tr("Start"),
326+
icon: "@FontAwesome5Solid/play/18",
327+
font: "text-18",
328+
allowGrowX: false,
329+
height: 32
330+
});
331+
startButton.addListener("execute", () => node.requestStartNode());
332+
loadingPage.addWidgetToMessages(startButton);
333+
}
334+
335+
if (status === "ready") {
336+
const msg = `Service ${node.getLabel()} ${status}`;
337+
const msgData = {
338+
nodeId: node.getNodeId(),
339+
msg,
340+
level: "INFO"
341+
};
342+
node.fireDataEvent("showInLogger", msgData);
343+
344+
// will switch to iframe's content
345+
this.__restartIFrame();
346+
if (!node.isDynamicV2()) {
347+
node.callRetrieveInputs();
348+
}
349+
} else if (["idle", "failed", "stopping"].includes(status) && oldStatus) {
350+
const msg = `Service ${node.getLabel()} ${status}`;
351+
const msgData = {
352+
nodeId: node.getNodeId(),
353+
msg,
354+
level: "INFO"
355+
};
356+
node.fireDataEvent("showInLogger", msgData);
357+
358+
// will switch to the loading page
359+
node.resetServiceUrl();
360+
this.getIFrame().resetSource();
361+
this.fireEvent("iframeChanged");
369362
}
370363
},
371364

@@ -394,7 +387,7 @@ qx.Class.define("osparc.data.model.IframeHandler", {
394387
const node = this.getNode();
395388
const status = node.getStatus().getInteractive();
396389
// it might have been stopped
397-
if (status === "ready") {
390+
if (["running", "ready"].includes(status)) {
398391
this.getIFrame().resetSource();
399392
this.getIFrame().setSource(node.getServiceUrl());
400393

services/static-webserver/client/source/class/osparc/data/model/Node.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -905,7 +905,7 @@ qx.Class.define("osparc.data.model.Node", {
905905
}
906906
};
907907
osparc.data.Resources.fetch("studies", "startNode", params)
908-
.then(() => this.startPollingState())
908+
.then(() => this.checkState())
909909
.catch(err => {
910910
if ("status" in err && (err.status === 409 || err.status === 402)) {
911911
osparc.FlashMessenger.getInstance().logAs(err.message, "WARNING");
@@ -1055,7 +1055,7 @@ qx.Class.define("osparc.data.model.Node", {
10551055
}
10561056
},
10571057

1058-
startPollingState: function() {
1058+
checkState: function() {
10591059
if (this.isDynamic()) {
10601060
const metadata = this.getMetaData();
10611061
const msg = "Starting " + metadata.key + ":" + metadata.version + "...";
@@ -1067,7 +1067,7 @@ qx.Class.define("osparc.data.model.Node", {
10671067
this.fireDataEvent("showInLogger", msgData);
10681068

10691069
if (this.getIframeHandler()) {
1070-
this.getIframeHandler().startPolling();
1070+
this.getIframeHandler().checkState();
10711071
} else {
10721072
console.error(this.getLabel() + " iframe handler not ready");
10731073
}

0 commit comments

Comments
 (0)