worked backup
This commit is contained in:
@@ -14,39 +14,107 @@
|
||||
import { get } from 'svelte/store';
|
||||
import { selectedTask, taskLogs } from '../lib/stores.js';
|
||||
import { getWsUrl } from '../lib/api.js';
|
||||
import { addToast } from '../lib/toasts.js';
|
||||
// [/SECTION]
|
||||
|
||||
let ws;
|
||||
let reconnectAttempts = 0;
|
||||
let maxReconnectAttempts = 10;
|
||||
let initialReconnectDelay = 1000;
|
||||
let maxReconnectDelay = 30000;
|
||||
let reconnectTimeout;
|
||||
let waitingForData = false;
|
||||
let dataTimeout;
|
||||
let connectionStatus = 'disconnected'; // 'connecting', 'connected', 'disconnected', 'waiting', 'completed'
|
||||
|
||||
// [DEF:connect:Function]
|
||||
/**
|
||||
* @purpose Establishes WebSocket connection with exponential backoff.
|
||||
*/
|
||||
function connect() {
|
||||
const task = get(selectedTask);
|
||||
if (!task || connectionStatus === 'completed') return;
|
||||
|
||||
console.log(`[TaskRunner][Entry] Connecting to logs for task: ${task.id} (Attempt ${reconnectAttempts + 1})`);
|
||||
connectionStatus = 'connecting';
|
||||
|
||||
const wsUrl = getWsUrl(task.id);
|
||||
ws = new WebSocket(wsUrl);
|
||||
|
||||
ws.onopen = () => {
|
||||
console.log('[TaskRunner][Coherence:OK] WebSocket connection established');
|
||||
connectionStatus = 'connected';
|
||||
reconnectAttempts = 0;
|
||||
startDataTimeout();
|
||||
};
|
||||
|
||||
ws.onmessage = (event) => {
|
||||
const logEntry = JSON.parse(event.data);
|
||||
taskLogs.update(logs => [...logs, logEntry]);
|
||||
resetDataTimeout();
|
||||
|
||||
// Check for completion message (if backend sends one)
|
||||
if (logEntry.message && logEntry.message.includes('Task completed successfully')) {
|
||||
connectionStatus = 'completed';
|
||||
ws.close();
|
||||
}
|
||||
};
|
||||
|
||||
ws.onerror = (error) => {
|
||||
console.error('[TaskRunner][Coherence:Failed] WebSocket error:', error);
|
||||
connectionStatus = 'disconnected';
|
||||
};
|
||||
|
||||
ws.onclose = (event) => {
|
||||
console.log(`[TaskRunner][Exit] WebSocket connection closed (Code: ${event.code})`);
|
||||
clearTimeout(dataTimeout);
|
||||
waitingForData = false;
|
||||
|
||||
if (connectionStatus !== 'completed' && reconnectAttempts < maxReconnectAttempts) {
|
||||
const delay = Math.min(initialReconnectDelay * Math.pow(2, reconnectAttempts), maxReconnectDelay);
|
||||
console.log(`[TaskRunner][Action] Reconnecting in ${delay}ms...`);
|
||||
reconnectTimeout = setTimeout(() => {
|
||||
reconnectAttempts++;
|
||||
connect();
|
||||
}, delay);
|
||||
} else if (reconnectAttempts >= maxReconnectAttempts) {
|
||||
console.error('[TaskRunner][Coherence:Failed] Max reconnect attempts reached.');
|
||||
addToast('Failed to connect to log stream after multiple attempts.', 'error');
|
||||
}
|
||||
};
|
||||
}
|
||||
// [/DEF:connect]
|
||||
|
||||
function startDataTimeout() {
|
||||
waitingForData = false;
|
||||
dataTimeout = setTimeout(() => {
|
||||
if (connectionStatus === 'connected') {
|
||||
waitingForData = true;
|
||||
}
|
||||
}, 5000);
|
||||
}
|
||||
|
||||
function resetDataTimeout() {
|
||||
clearTimeout(dataTimeout);
|
||||
waitingForData = false;
|
||||
startDataTimeout();
|
||||
}
|
||||
|
||||
// [DEF:onMount:Function]
|
||||
/**
|
||||
* @purpose Initialize WebSocket connection for task logs.
|
||||
*/
|
||||
onMount(() => {
|
||||
const task = get(selectedTask);
|
||||
if (task) {
|
||||
console.log(`[TaskRunner][Entry] Connecting to logs for task: ${task.id}`);
|
||||
taskLogs.set([]); // Clear previous logs
|
||||
const wsUrl = getWsUrl(task.id);
|
||||
ws = new WebSocket(wsUrl);
|
||||
|
||||
ws.onopen = () => {
|
||||
console.log('[TaskRunner][Coherence:OK] WebSocket connection established');
|
||||
};
|
||||
|
||||
ws.onmessage = (event) => {
|
||||
const logEntry = JSON.parse(event.data);
|
||||
taskLogs.update(logs => [...logs, logEntry]);
|
||||
};
|
||||
|
||||
ws.onerror = (error) => {
|
||||
console.error('[TaskRunner][Coherence:Failed] WebSocket error:', error);
|
||||
};
|
||||
|
||||
ws.onclose = () => {
|
||||
console.log('[TaskRunner][Exit] WebSocket connection closed');
|
||||
};
|
||||
}
|
||||
// Subscribe to selectedTask changes
|
||||
const unsubscribe = selectedTask.subscribe(task => {
|
||||
if (task) {
|
||||
console.log(`[TaskRunner][Action] Task selected: ${task.id}. Initializing connection.`);
|
||||
if (ws) ws.close();
|
||||
clearTimeout(reconnectTimeout);
|
||||
reconnectAttempts = 0;
|
||||
connectionStatus = 'disconnected';
|
||||
taskLogs.set([]);
|
||||
connect();
|
||||
}
|
||||
});
|
||||
return unsubscribe;
|
||||
});
|
||||
// [/DEF:onMount]
|
||||
|
||||
@@ -55,6 +123,8 @@
|
||||
* @purpose Close WebSocket connection when the component is destroyed.
|
||||
*/
|
||||
onDestroy(() => {
|
||||
clearTimeout(reconnectTimeout);
|
||||
clearTimeout(dataTimeout);
|
||||
if (ws) {
|
||||
console.log("[TaskRunner][Action] Closing WebSocket connection.");
|
||||
ws.close();
|
||||
@@ -66,8 +136,29 @@
|
||||
<!-- [SECTION: TEMPLATE] -->
|
||||
<div class="p-4 border rounded-lg bg-white shadow-md">
|
||||
{#if $selectedTask}
|
||||
<h2 class="text-xl font-semibold mb-2">Task: {$selectedTask.plugin_id}</h2>
|
||||
<div class="bg-gray-900 text-white font-mono text-sm p-4 rounded-md h-96 overflow-y-auto">
|
||||
<div class="flex justify-between items-center mb-2">
|
||||
<h2 class="text-xl font-semibold">Task: {$selectedTask.plugin_id}</h2>
|
||||
<div class="flex items-center space-x-2">
|
||||
{#if connectionStatus === 'connecting'}
|
||||
<span class="flex h-3 w-3 relative">
|
||||
<span class="animate-ping absolute inline-flex h-full w-full rounded-full bg-yellow-400 opacity-75"></span>
|
||||
<span class="relative inline-flex rounded-full h-3 w-3 bg-yellow-500"></span>
|
||||
</span>
|
||||
<span class="text-xs text-gray-500">Connecting...</span>
|
||||
{:else if connectionStatus === 'connected'}
|
||||
<span class="h-3 w-3 rounded-full bg-green-500"></span>
|
||||
<span class="text-xs text-gray-500">Live</span>
|
||||
{:else if connectionStatus === 'completed'}
|
||||
<span class="h-3 w-3 rounded-full bg-blue-500"></span>
|
||||
<span class="text-xs text-gray-500">Completed</span>
|
||||
{:else}
|
||||
<span class="h-3 w-3 rounded-full bg-red-500"></span>
|
||||
<span class="text-xs text-gray-500">Disconnected</span>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="bg-gray-900 text-white font-mono text-sm p-4 rounded-md h-96 overflow-y-auto relative">
|
||||
{#each $taskLogs as log}
|
||||
<div>
|
||||
<span class="text-gray-400">{new Date(log.timestamp).toLocaleTimeString()}</span>
|
||||
@@ -75,6 +166,12 @@
|
||||
<span>{log.message}</span>
|
||||
</div>
|
||||
{/each}
|
||||
|
||||
{#if waitingForData}
|
||||
<div class="text-gray-500 italic mt-2 animate-pulse">
|
||||
Waiting for data...
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
{:else}
|
||||
<p>No task selected.</p>
|
||||
|
||||
Reference in New Issue
Block a user