You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@texera.apache.org by "eugenegujing (via GitHub)" <gi...@apache.org> on 2026/10/05 08:11:49 UTC
[I] one failed request permanently stops the computing-unit list refresh and the selected-unit poll [texera]
eugenegujing opened a new issue, #8850:
URL: https://github.com/apache/texera/issues/8850
### What happened?
`ComputingUnitStatusService` keeps the computing-unit list and the selected unit's status fresh through two RxJS pipelines. Both are built the same way, and both have the same flaw: the inner HTTP observable has no error handling, so an HTTP error propagates out of the `switchMap`, reaches a `subscribe` that has no error callback, and terminates the subscription. Nothing ever re-creates it.
The list refresh:
```ts
// frontend/src/app/common/service/computing-unit/computing-unit-status/computing-unit-status.service.ts:141-155
private startRefreshInterval(): void {
if (this.refreshSubscription) {
this.refreshSubscription.unsubscribe();
}
this.refreshSubscription = this.refreshComputingUnitListSignal
.pipe(
switchMap(() => this.computingUnitService.listComputingUnits()),
untilDestroyed(this)
)
.subscribe(units => {
this.setComputingUnitsState(units);
});
}
```
The poll of the selected unit:
```ts
// frontend/src/app/common/service/computing-unit/computing-unit-status/computing-unit-status.service.ts:91-104
private startPollingSelectedUnit(cuid: number): void {
// cancel previous poll, if any
this.selectedUnitPoll?.unsubscribe();
this.selectedUnitPoll = interval(this.REFRESH_INTERVAL_MS)
.pipe(
// each tick → get fresh data for *this* cuid
switchMap(() => this.computingUnitService.getComputingUnit(cuid)),
untilDestroyed(this)
)
.subscribe(unit => {
this.updateUnitInList(unit);
}); // merge into cache
}
```
In RxJS an `error` is a terminal notification: `switchMap` forwards an inner error to its downstream unchanged, and a subscriber that receives it is closed for good. The service is `providedIn: "root"` and the refresh subscription is created exactly once, from the constructor. After a single failed list call, `refreshComputingUnitList()` keeps pushing into a `Subject` that no longer has a subscriber, for the rest of the page's life. The same happens to the poll on its first failed `getComputingUnit`. The only trace is one `ERROR HttpErrorResponse` line that Angular's global error handler prints to the console.
The failure that kills the pipeline can be anything the backend or the network produces: a 500, a 502 or 504 from the proxy while the computing-unit managing service restarts, or a transient connection error. Neither HTTP interceptor swallows errors (`unauthorized-http-interceptor.service.ts`, `blob-error-http-interceptor.service.ts` both rethrow), so nothing upstream stops the error before it reaches the pipeline.
What the user sees afterwards, until the page is reloaded:
- **Dashboard.** The Computing Units page asks for a refresh every second (`user-computing-unit.component.ts:94-98`), so it is the likeliest place to hit a transient error. From then on the list is frozen: units created elsewhere never appear, terminated units never disappear.
- **Workspace dropdown.** Opening the computing-unit dropdown (`computing-unit-selection.component.ts:903`) no longer refreshes anything.
- **Selected unit.** Once the poll is dead, the selected unit's status never changes again. A unit that dies keeps showing its last status, and none of the Failed / Terminating / reason states added by #7944 can reach the UI.
- **Canvas run button.** Its text and disabled flag are recomputed on `getStatus()` emissions (`menu.component.ts`). With the poll dead those emissions stop, so the button can stay on "Connecting" after the socket is actually up, because the server's `WorkflowStateEvent("Uninitialized")` on connect emits nothing when the frontend is already Uninitialized (`execute-workflow.service.ts`).
Note that `terminateComputingUnit()` in the same file does guard its own request with `catchError`, so the two long-lived pipelines are the only unguarded ones in the service.
### How to reproduce?
Reproduced in Chrome on a locally running stack. The failing request was produced by making exactly one `GET api/computing-unit` fail from the browser and letting all later ones through.
1. Open Dashboard → Compute. The page requests the list once a second.
2. Let one of those requests fail. The console shows one `ERROR HttpErrorResponse`.
3. No further list request is sent, however long the page stays open.
4. From a second tab, create or terminate a computing unit. The second tab shows the change at once; the first tab never does, until it is reloaded.
The selected-unit poll (`GET api/computing-unit/<cuid>` every 2 s) stops the same way after one failed request.
Without instrumenting the browser: open the Dashboard's Compute page, stop the computing-unit managing service for a few seconds so that at least one refresh fails, start it again, then change a unit from another tab.
### Version/Branch
1.4.0-incubating-SNAPSHOT (main)
### Commit Hash (Optional)
_No response_
### What browsers are you seeing the problem on?
_No response_
### Relevant log output
```shell
```
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: notifications-unsubscribe@texera.apache.org.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org