This is an automated email from the ASF dual-hosted git repository.
chanholee pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/zeppelin.git
The following commit(s) were added to refs/heads/master by this push:
new 705110aa12 [ZEPPELIN-6387] Fix WebSocket reconnection not reloading
note in Angular UI
705110aa12 is described below
commit 705110aa120fb9180425252c755d499cf086f5ff
Author: ChanHo Lee <[email protected]>
AuthorDate: Sun Apr 5 14:57:50 2026 +0900
[ZEPPELIN-6387] Fix WebSocket reconnection not reloading note in Angular UI
### What is this PR for?
Fixes an issue where WebSocket reconnection in the new Angular UI
(zeppelin-web-angular) does not reload the current note, causing "Note is null"
errors when attempting to run paragraphs after reconnection.
### What type of PR is it?
Bug Fix
### What is the Jira issue?
https://issues.apache.org/jira/browse/ZEPPELIN-6387
### How should this be tested?
1. Open any notebook in the new Angular UI.
2. Trigger a WebSocket timeout by switching to another browser tab or
window and leaving the Zeppelin tab in the background for a few minutes.
- Even without interacting with the browser, you can confirm that the
WebSocket has reconnected by checking the server logs.
3. Allow the system to automatically reconnect.
4. Try running any paragraph → It should fail before this PR and succeed
after applying this PR.
### Questions:
* Does the license files need to update? No
* Is there breaking changes for older versions? No
* Does this needs documentation? No
Closes #5129 from tbonelee/websocket-reconnection.
Signed-off-by: ChanHo Lee <[email protected]>
---
.../projects/zeppelin-sdk/src/message.ts | 20 +++++++++++++-
.../pages/workspace/notebook/notebook.component.ts | 31 +++++++++++++++-------
2 files changed, 41 insertions(+), 10 deletions(-)
diff --git a/zeppelin-web-angular/projects/zeppelin-sdk/src/message.ts
b/zeppelin-web-angular/projects/zeppelin-sdk/src/message.ts
index f63f693fe8..29a05ddf8c 100644
--- a/zeppelin-web-angular/projects/zeppelin-sdk/src/message.ts
+++ b/zeppelin-web-angular/projects/zeppelin-sdk/src/message.ts
@@ -43,6 +43,7 @@ export class Message {
public connectedStatus = false;
public connectedStatus$ = new Subject<boolean>();
private ws: WebSocketSubject<WebSocketMessage<MessageDataTypeMap>> | null =
null;
+ private wsSubscription: Subscription | null = null;
private open$ = new Subject<Event>();
private close$ = new Subject<CloseEvent>();
private sent$ = new Subject<WebSocketMessage<MessageSendDataTypeMap>>();
@@ -99,13 +100,26 @@ export class Message {
if (!this.wsUrl) {
throw new Error('WebSocket URL is not set. Please call setWsUrl() before
connect()');
}
+
+ // Unsubscribe from existing subscription first
+ if (this.wsSubscription) {
+ this.wsSubscription.unsubscribe();
+ this.wsSubscription = null;
+ }
+
+ // Then close existing WebSocket
+ if (this.ws) {
+ this.ws.complete();
+ this.ws = null;
+ }
+
this.ws = webSocket<WebSocketMessage<MessageDataTypeMap>>({
url: this.wsUrl,
openObserver: this.open$,
closeObserver: this.close$
});
- this.ws
+ this.wsSubscription = this.ws
.pipe(
// reconnect
retryWhen(errors => errors.pipe(mergeMap(() =>
this.close$.pipe(take(1), delay(4000)))))
@@ -190,6 +204,10 @@ export class Message {
}
destroy(): void {
+ if (this.wsSubscription) {
+ this.wsSubscription.unsubscribe();
+ this.wsSubscription = null;
+ }
if (this.ws) {
this.ws.complete();
this.ws = null;
diff --git
a/zeppelin-web-angular/src/app/pages/workspace/notebook/notebook.component.ts
b/zeppelin-web-angular/src/app/pages/workspace/notebook/notebook.component.ts
index b22cd012d3..ff73912d18 100644
---
a/zeppelin-web-angular/src/app/pages/workspace/notebook/notebook.component.ts
+++
b/zeppelin-web-angular/src/app/pages/workspace/notebook/notebook.component.ts
@@ -435,18 +435,31 @@ export class NotebookComponent extends
MessageListenersManager implements OnInit
this.noteVarShareService.clear();
});
this.activatedRoute.params.pipe(takeUntil(this.destroy$)).subscribe(param
=> {
- const { noteId, revisionId } = param;
- if (revisionId) {
- this.messageService.noteRevision(noteId, revisionId);
- } else {
- this.messageService.getNote(noteId);
- }
- this.revisionView = !!revisionId;
+ this.revisionView = !!param.revisionId;
this.cdr.markForCheck();
- this.messageService.listRevisionHistory(noteId);
- // TODO(hsuanxyz) scroll to current paragraph
});
this.revisionView = !!this.activatedRoute.snapshot.params.revisionId;
+
+ // Fetch note when WebSocket connects or reconnects
+ this.messageService.connectedStatus$
+ .pipe(startWith(this.messageService.connectedStatus),
takeUntil(this.destroy$))
+ .subscribe(connected => {
+ console.log('connectedStatus$ changed to ', connected ? 'connected' :
'disconnected');
+ if (connected) {
+ const { noteId, revisionId } = this.activatedRoute.snapshot.params;
+ if (!noteId) {
+ throw new Error('Route parameter `noteId` is required.');
+ }
+ if (revisionId) {
+ this.messageService.noteRevision(noteId, revisionId);
+ } else {
+ this.messageService.getNote(noteId);
+ }
+ this.cdr.markForCheck();
+ this.messageService.listRevisionHistory(noteId);
+ // TODO(hsuanxyz) scroll to current paragraph
+ }
+ });
}
removeParagraphFromNgZ(): void {