This is an automated email from the ASF dual-hosted git repository.
tbonelee 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 1bcd87198e [ZEPPELIN-6419] Fix clone paragraph content loss caused by
shortCircuit seq filtering
1bcd87198e is described below
commit 1bcd87198e94c1d46384775d0f22de665ee6e4b6
Author: Manhua <[email protected]>
AuthorDate: Wed Jun 3 13:19:20 2026 +0800
[ZEPPELIN-6419] Fix clone paragraph content loss caused by shortCircuit seq
filtering
### What is this PR for?
**Problem**
When cloning a paragraph in zeppelin-web-angular, the cloned paragraph only
contains the interpreter binding (e.g., %mysql) but not the actual editor
content (e.g., select 1 a, 2 a). The old zeppelin-web handles this correctly.
**Root Cause Analysis**
The backend copyParagraph is a two-step operation:
```
1. insertParagraph() → broadcasts PARAGRAPH_ADDED (empty new paragraph,
text="%mysql\n")
2. updateParagraph() → broadcasts PARAGRAPH (full
text="%mysql\nselect 1 a, 2 a")
```
Step 2's PARAGRAPH response gets silently discarded by the frontend
shortCircuit mechanism in message.ts. The original filter logic compares the
currently-sent message sequence number against the received response's sequence
number:
```ts
// OLD logic — overly aggressive
if (this.lastMsgIdSeqSent > msgIdSeqReceived) {
// "message is already updated by shortcircuit" → discard!
return false;
}
```
The problem: between sending COPY_PARAGRAPH (seq=49) and receiving its
PARAGRAPH response, other unrelated messages like EDITOR_SETTING (seq=50) may
be sent. This makes lastMsgIdSeqSent (50) > msgIdSeqReceived (49), causing the
legitimate PARAGRAPH response for the cloned paragraph to be incorrectly
filtered out.
<img width="807" height="951" alt="image"
src="https://github.com/user-attachments/assets/3395e3eb-352c-45f7-96ca-68d3d3f5a983"
/>
~~**Solution**
Replace the implicit sequence-number comparison with an explicit tracking
set (shortCircuitedParagraphMsgIds). Only messages that were explicitly passed
to shortCircuit() get filtered — not all messages where lastMsgIdSeqSent >
receivedSeq.~~
**Updated Solution**
Dropping the PARAGRAPH msgId compare filter branch when received msg
### What type of PR is it?
Bug Fix
### Todos
* [ ] - Task
### What is the Jira issue?
* Open an issue on Jira https://issues.apache.org/jira/browse/ZEPPELIN/
* Put link here, and add [ZEPPELIN-*Jira number*] in PR title, eg.
[ZEPPELIN-533]
### How should this be tested?
* Strongly recommended: add automated unit tests for any new or changed
behavior
* Outline any manual steps to test the PR here.
### Screenshots (if appropriate)
### Questions:
* Does the license files need to update?
* Is there breaking changes for older versions?
* Does this needs documentation?
Closes #5254 from kevinjmh/ZEPPELIN-6419.
Signed-off-by: ChanHo Lee <[email protected]>
---
.../src/interfaces/message-paragraph.interface.ts | 4 ++--
.../projects/zeppelin-sdk/src/message.ts | 22 +---------------------
2 files changed, 3 insertions(+), 23 deletions(-)
diff --git
a/zeppelin-web-angular/projects/zeppelin-sdk/src/interfaces/message-paragraph.interface.ts
b/zeppelin-web-angular/projects/zeppelin-sdk/src/interfaces/message-paragraph.interface.ts
index 689104668d..2ea3916ea1 100644
---
a/zeppelin-web-angular/projects/zeppelin-sdk/src/interfaces/message-paragraph.interface.ts
+++
b/zeppelin-web-angular/projects/zeppelin-sdk/src/interfaces/message-paragraph.interface.ts
@@ -77,10 +77,10 @@ export interface ParagraphConfig {
}
export interface ParagraphResults {
+ [index: number]: Record<string, unknown>;
+
code?: string;
msg?: ParagraphIResultsMsgItem[];
-
- [index: number]: Record<string, unknown>;
}
export enum DatasetType {
diff --git a/zeppelin-web-angular/projects/zeppelin-sdk/src/message.ts
b/zeppelin-web-angular/projects/zeppelin-sdk/src/message.ts
index 4f8c5e625b..42821062eb 100644
--- a/zeppelin-web-angular/projects/zeppelin-sdk/src/message.ts
+++ b/zeppelin-web-angular/projects/zeppelin-sdk/src/message.ts
@@ -52,6 +52,7 @@ export class Message {
private wsUrl?: string;
private ticket?: Ticket;
private uniqueClientId = Math.random().toString(36).substring(2, 7);
+ // TODO: Clean up this variable with `msgId` in server-side. See
ZEPPELIN-6419, ZEPPELIN-4985
private lastMsgIdSeqSent = 0;
private readonly normalCloseCode = 1000;
@@ -174,27 +175,6 @@ export class Message {
receive<K extends keyof MessageReceiveDataTypeMap>(op: K):
Observable<Record<K, MessageReceiveDataTypeMap[K]>[K]> {
return this.received$.pipe(
filter(message => message.op === op),
- filter(message => {
- if (!message.msgId) {
- // when msgId is not specified, it is not response to client request.
- // always process them
- return true;
- }
- const uniqueClientId = message.msgId.split('-')[0];
- const msgIdSeqReceived = parseInt(message.msgId.split('-')[1], 10);
- const isResponseForRequestFromThisClient = uniqueClientId ===
this.uniqueClientId;
-
- if (message.op === OP.PARAGRAPH) {
- if (isResponseForRequestFromThisClient && this.lastMsgIdSeqSent >
msgIdSeqReceived) {
- console.log('PARAPGRAPH is already updated by shortcircuit');
- return false;
- } else {
- return true;
- }
- } else {
- return true;
- }
- }),
map(message => message.data)
) as Observable<Record<K, MessageReceiveDataTypeMap[K]>[K]>;
}