Files
2025-12-02 16:27:21 +00:00

205 lines
7.9 KiB
Plaintext

// ============================================================================
// STARTUP RECOVERY Function - Session State Restoration (Issue 1)
// Purpose: Restore session state from database on Node-RED startup/crash recovery
// Trigger: Inject node on startup
// Outputs: 2 (UI notification, database query)
// ============================================================================
// This function should be called on Node-RED startup (via inject node with "inject once after X seconds")
// It queries the session_state table and restores global variables
const mode = msg.mode || "check";
switch (mode) {
// ========================================================================
// STEP 1: Query database for session state
// ========================================================================
case "check": {
msg._mode = "query-session-state";
msg.topic = "SELECT * FROM session_state WHERE session_key = 'current_session';";
node.warn("[RECOVERY] Checking for existing session state...");
return [null, msg];
}
// ========================================================================
// STEP 2: Process query results and prompt user
// ========================================================================
case "process-results": {
const results = msg.payload;
if (!results || results.length === 0) {
node.warn("[RECOVERY] No session state found in database");
return [null, null];
}
const session = results[0];
// Check if there's a valid session to restore
if (!session.work_order_id || session.cycle_count === 0) {
node.warn("[RECOVERY] Session state exists but is empty - nothing to restore");
return [null, null];
}
// Check if tracking was enabled
if (!session.tracking_enabled) {
node.warn("[RECOVERY] Previous session was not actively tracking - restoring state without prompt");
// Restore the state silently
global.set("cycleCount", session.cycle_count || 0);
global.set("productionStartTime", session.production_start_time);
global.set("operatingTime", Number(session.operating_time) || 0);
global.set("downtime", Number(session.downtime) || 0);
global.set("lastUpdateTime", session.last_update_time || Date.now());
global.set("trackingEnabled", false);
global.set("scrapPromptIssuedFor", session.scrap_prompt_issued_for || null);
global.set("currentSessionId", session.current_session_id || null);
return [null, null];
}
// Session was actively tracking - prompt user
node.warn(`[RECOVERY] Found active session - Work Order: ${session.work_order_id}, Cycles: ${session.cycle_count}`);
const promptMsg = {
_mode: "recovery-prompt",
recoveryPrompt: {
workOrderId: session.work_order_id,
cycleCount: session.cycle_count,
operatingTime: Number(session.operating_time) || 0,
downtime: Number(session.downtime) || 0,
timestamp: session.last_update_time,
sessionData: session
}
};
return [promptMsg, null];
}
// ========================================================================
// STEP 3: User chose to restore session
// ========================================================================
case "restore": {
const sessionData = msg.payload;
if (!sessionData) {
node.error("[RECOVERY] No session data provided for restore");
return [null, null];
}
node.warn(`[RECOVERY] Restoring session - Work Order: ${sessionData.work_order_id}, Cycles: ${sessionData.cycle_count}`);
// Restore all global variables
global.set("cycleCount", sessionData.cycle_count || 0);
global.set("productionStartTime", sessionData.production_start_time);
global.set("operatingTime", Number(sessionData.operating_time) || 0);
global.set("downtime", Number(sessionData.downtime) || 0);
global.set("lastUpdateTime", sessionData.last_update_time || Date.now());
global.set("trackingEnabled", !!sessionData.tracking_enabled);
global.set("scrapPromptIssuedFor", sessionData.scrap_prompt_issued_for || null);
global.set("currentSessionId", sessionData.current_session_id || null);
// Also need to restore activeWorkOrder from work_orders table
const queryMsg = {
_mode: "query-work-order",
topic: `SELECT * FROM work_orders WHERE work_order_id = '${sessionData.work_order_id}';`
};
const notificationMsg = {
_mode: "recovery-success",
notification: {
message: `Session restored: ${sessionData.work_order_id} - ${sessionData.cycle_count} cycles`,
type: "success"
}
};
return [notificationMsg, queryMsg];
}
// ========================================================================
// STEP 4: Set activeWorkOrder from query result
// ========================================================================
case "set-work-order": {
const results = msg.payload;
if (!results || results.length === 0) {
node.error("[RECOVERY] Work order not found in database");
return [null, null];
}
const workOrder = results[0];
// Reconstruct activeWorkOrder object
const activeOrder = {
id: workOrder.work_order_id,
sku: workOrder.sku,
target: workOrder.target,
good: workOrder.good_parts,
scrap: workOrder.scrap_count || 0,
cycleTime: workOrder.cycle_time,
theoreticalCycleTime: workOrder.cycle_time,
progressPercent: workOrder.progress_percent,
status: workOrder.status,
lastUpdateIso: new Date().toISOString()
};
global.set("activeWorkOrder", activeOrder);
node.warn(`[RECOVERY] Active work order restored: ${activeOrder.id}`);
return [null, null];
}
// ========================================================================
// STEP 5: User chose to start fresh
// ========================================================================
case "start-fresh": {
node.warn("[RECOVERY] User chose to start fresh - clearing session state");
// Clear all global variables
global.set("cycleCount", 0);
global.set("productionStartTime", null);
global.set("operatingTime", 0);
global.set("downtime", 0);
global.set("lastUpdateTime", Date.now());
global.set("trackingEnabled", false);
global.set("activeWorkOrder", null);
global.set("scrapPromptIssuedFor", null);
global.set("currentSessionId", null);
// Clear session_state in database
const clearMsg = {
_mode: "clear-session-state",
topic: `
UPDATE session_state
SET
work_order_id = NULL,
cycle_count = 0,
production_start_time = NULL,
operating_time = 0,
downtime = 0,
last_update_time = NULL,
tracking_enabled = 0,
machine_state = 0,
scrap_prompt_issued_for = NULL,
current_session_id = NULL
WHERE session_key = 'current_session';
`
};
const notificationMsg = {
_mode: "recovery-cleared",
notification: {
message: "Started with fresh session",
type: "info"
}
};
return [notificationMsg, clearMsg];
}
}
// Default
return [null, null];