Files
openobserve/web/src/workers/streamWorker.js
T
Omkar Kesarkhane b03245cd07 fix: http and http2 partition pagination fixes (#7241)
### **PR Type**
Bug fix, Enhancement


___

### **Description**
Fix HTTP/HTTP2 streaming in Safari
Improve partition-based pagination logic
Add region and cluster query parameters
Refine aggregation and streaming pagination flows


___



### **Changes walkthrough** 📝
<table><thead><tr><th></th><th align="left">Relevant
files</th></tr></thead><tbody><tr><td><strong>Bug
fix</strong></td><td><table>
<tr>
  <td>
    <details>
<summary><strong>ShortUrl.vue</strong><dd><code>Fix original URL
redirection for deeper paths</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></summary>
<hr>

web/src/views/ShortUrl.vue

- Updated handleOriginalUrl to join URL segments dynamically


</details>


  </td>
<td><a
href="https://github.com/openobserve/openobserve/pull/7241/files#diff-b7ffcc5de24f9e1db5a3a8e78a686727360f9061ca6f9f8ae60456c3d603f9b7">+3/-2</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
  <td>
    <details>
<summary><strong>useStreamingSearch.ts</strong><dd><code>Add
Safari-compatible HTTP2 streaming</code>&nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></summary>
<hr>

web/src/composables/useStreamingSearch.ts

<li>Manually read streams with TextDecoder for Safari<br> <li> Post
decoded chunks to worker for processing<br> <li> Retain start and end
stream control messages


</details>


  </td>
<td><a
href="https://github.com/openobserve/openobserve/pull/7241/files#diff-8fce3e25a161cd458e734bd9b1f98aadefe3482da7b6529a5b1f4fa20ec115e2">+37/-4</a>&nbsp;
&nbsp; </td>

</tr>
</table></td></tr><tr><td><strong>Enhancement</strong></td><td><table>
<tr>
  <td>
    <details>
<summary><strong>useLogs.ts</strong><dd><code>Enhance log pagination and
cluster support</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></summary>
<hr>

web/src/composables/useLogs.ts

<li>Inject regions and clusters into query and URL<br> <li> Fix
partition pagination for zero or multiple partitions<br> <li> Add
fetchAllParitions for complete partition fetch<br> <li> Apply dynamic
histogram_interval to SQL queries


</details>


  </td>
<td><a
href="https://github.com/openobserve/openobserve/pull/7241/files#diff-1040f61354f92711e0e77ed4e9bfa15586d45a94c7e2ab06cc37372068030e7b">+116/-23</a></td>

</tr>

<tr>
  <td>
    <details>
<summary><strong>streamWorker.js</strong><dd><code>Refactor worker for
chunk-based streaming</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
</dd></summary>
<hr>

web/src/workers/streamWorker.js

<li>Remove transferable ReadableStream handling<br> <li> Introduce
processChunk to buffer and parse SSE<br> <li> Consolidate message
parsing and error handling


</details>


  </td>
<td><a
href="https://github.com/openobserve/openobserve/pull/7241/files#diff-8534facfcca68c16701832f43a501abcdb92847115c46fced5d69792e5594dd9">+75/-94</a>&nbsp;
</td>

</tr>
</table></td></tr></tr></tbody></table>

___

> <details> <summary> Need help?</summary><li>Type <code>/help how to
...</code> in the comments thread for any questions about PR-Agent
usage.</li><li>Check out the <a
href="https://qodo-merge-docs.qodo.ai/usage-guide/">documentation</a>
for more information.</li></details>
2025-06-29 14:18:25 +05:30

133 lines
3.7 KiB
JavaScript

// Worker to handle stream processing
// This offloads decoding and parsing from the main thread
let activeBuffers = {};
// Helper function to extract data from message line
function extractData(line) {
return line.startsWith('data:') ? line.slice(6) : line.slice(5);
}
// Handle messages from main thread
self.onmessage = async (event) => {
const { action, traceId, chunk } = event.data;
switch (action) {
case 'startStream':
// For Safari compatibility, we receive chunks instead of streams
activeBuffers[traceId] = '';
break;
case 'processChunk':
// Process individual chunk (Safari compatibility)
if (activeBuffers[traceId] !== undefined) {
processChunk(traceId, chunk);
}
break;
case 'endStream':
// Stream ended, send end notification
self.postMessage({
type: 'end',
traceId,
});
delete activeBuffers[traceId];
break;
case 'cancelStream':
delete activeBuffers[traceId];
break;
case 'closeAll':
activeBuffers = {};
break;
}
};
// Process a chunk for a given traceId
function processChunk(traceId, chunk) {
let buffer = activeBuffers[traceId] || '';
try {
// Add chunk to buffer
buffer += chunk;
// Process complete messages
const messages = buffer.split('\n\n');
// Keep the last potentially incomplete message in buffer
buffer = messages.pop() || '';
activeBuffers[traceId] = buffer;
const lines = messages.filter(line => line.trim());
// Process each complete line
for (let i = 0; i < lines.length; i++) {
try {
const msgLines = lines[i].split('\n');
// Check if this is an event line
if(msgLines.length > 1){
const eventType = msgLines[0].startsWith('event:') ? msgLines[0].slice(7).trim() : msgLines[0].slice(6).trim();
//TODO: Logic is duplicated for event:search_response and event:search_response_hits
// Create method to handle this
if (msgLines[1]?.startsWith('data:') || msgLines[1]?.startsWith('data: ')) {
const data = extractData(msgLines[1]);
try {
// Try to parse as JSON
const json = JSON.parse(data);
// Send message based on event type
self.postMessage({
type: eventType,
traceId,
data: json,
});
} catch (parseErr) {
// If JSON parsing fails, send raw data
self.postMessage({
type: 'error',
traceId,
data: { message: 'Error parsing data', error: parseErr.toString() },
});
}
}
}
if (msgLines[0]?.startsWith('data:') || msgLines[0]?.startsWith('data: ')) {
const data = extractData(msgLines[0]);
try {
// Try to parse as JSON
const json = JSON.parse(data);
// Send message based on event type
self.postMessage({
type: 'data',
traceId,
data: json,
});
} catch (parseErr) {
// If JSON parsing fails, send raw data
self.postMessage({
type: 'data',
traceId,
data: data,
});
}
}
} catch (e) {
self.postMessage({
type: 'error',
traceId,
data: { message: 'Error processing message', error: e.toString() },
});
}
}
} catch (error) {
// Send error to main thread
self.postMessage({
type: 'error',
traceId,
data: { message: 'Stream processing error', error: error.toString() },
});
}
}