Optimize metrics import and split off metrics import functions (untested)

This commit is contained in:
2025-01-11 14:52:47 -05:00
parent 30018ad882
commit eed032735d
7 changed files with 1082 additions and 254 deletions

View File

@@ -17,6 +17,7 @@ let importProgress = null;
const updateClients = new Set();
const importClients = new Set();
const resetClients = new Set();
const resetMetricsClients = new Set();
// Helper to send progress to specific clients
function sendProgressToClients(clients, progress) {
@@ -107,6 +108,28 @@ router.get('/reset/progress', (req, res) => {
});
});
// Add reset-metrics progress endpoint
router.get('/reset-metrics/progress', (req, res) => {
res.writeHead(200, {
'Content-Type': 'text/event-stream',
'Cache-Control': 'no-cache',
'Connection': 'keep-alive',
'Access-Control-Allow-Origin': req.headers.origin || '*',
'Access-Control-Allow-Credentials': 'true'
});
// Send an initial message to test the connection
res.write('data: {"status":"running","operation":"Initializing connection..."}\n\n');
// Add this client to the reset-metrics set
resetMetricsClients.add(res);
// Remove client when connection closes
req.on('close', () => {
resetMetricsClients.delete(res);
});
});
// Debug endpoint to verify route registration
router.get('/test', (req, res) => {
console.log('CSV test endpoint hit');
@@ -434,4 +457,104 @@ router.post('/reset', async (req, res) => {
}
});
// Add reset-metrics endpoint
router.post('/reset-metrics', async (req, res) => {
if (activeImport) {
res.status(400).json({ error: 'Operation already in progress' });
return;
}
try {
// Set active import to prevent concurrent operations
activeImport = {
type: 'reset-metrics',
status: 'running',
operation: 'Starting metrics reset'
};
// Send initial response
res.status(200).json({ message: 'Reset metrics started' });
// Send initial progress through SSE
sendProgressToClients(resetMetricsClients, {
status: 'running',
operation: 'Starting metrics reset'
});
// Run the reset metrics script
const resetMetrics = require('../../scripts/reset-metrics');
await resetMetrics();
// Send completion through SSE
sendProgressToClients(resetMetricsClients, {
status: 'complete',
operation: 'Metrics reset completed'
});
activeImport = null;
} catch (error) {
console.error('Error during metrics reset:', error);
// Send error through SSE
sendProgressToClients(resetMetricsClients, {
status: 'error',
error: error.message || 'Failed to reset metrics'
});
activeImport = null;
res.status(500).json({ error: error.message || 'Failed to reset metrics' });
}
});
// Add calculate-metrics endpoint
router.post('/calculate-metrics', async (req, res) => {
if (activeImport) {
res.status(400).json({ error: 'Operation already in progress' });
return;
}
try {
// Set active import to prevent concurrent operations
activeImport = {
type: 'calculate-metrics',
status: 'running',
operation: 'Starting metrics calculation'
};
// Send initial response
res.status(200).json({ message: 'Metrics calculation started' });
// Send initial progress through SSE
sendProgressToClients(importClients, {
status: 'running',
operation: 'Starting metrics calculation',
percentage: '0'
});
// Run the metrics calculation script
const calculateMetrics = require('../../scripts/calculate-metrics');
await calculateMetrics();
// Send completion through SSE
sendProgressToClients(importClients, {
status: 'complete',
operation: 'Metrics calculation completed',
percentage: '100'
});
activeImport = null;
} catch (error) {
console.error('Error during metrics calculation:', error);
// Send error through SSE
sendProgressToClients(importClients, {
status: 'error',
error: error.message || 'Failed to calculate metrics'
});
activeImport = null;
res.status(500).json({ error: error.message || 'Failed to calculate metrics' });
}
});
module.exports = router;

View File

@@ -1,6 +1,8 @@
const express = require('express');
const cors = require('cors');
const { spawn } = require('child_process');
const path = require('path');
const fs = require('fs');
const express = require('express');
const mysql = require('mysql2/promise');
const { corsMiddleware, corsErrorHandler } = require('./middleware/cors');
const { initPool } = require('./utils/db');
@@ -127,6 +129,111 @@ pool.getConnection()
process.exit(1);
});
// Initialize client sets for SSE
const importClients = new Set();
const updateClients = new Set();
const resetClients = new Set();
const resetMetricsClients = new Set();
// Helper function to send progress to SSE clients
const sendProgressToClients = (clients, data) => {
clients.forEach(client => {
try {
client.write(`data: ${JSON.stringify(data)}\n\n`);
} catch (error) {
console.error('Error sending SSE update:', error);
}
});
};
// Setup SSE connection
const setupSSE = (req, res) => {
const { type } = req.params;
// Set headers for SSE
res.writeHead(200, {
'Content-Type': 'text/event-stream',
'Cache-Control': 'no-cache',
'Connection': 'keep-alive',
'Access-Control-Allow-Origin': req.headers.origin || '*',
'Access-Control-Allow-Credentials': 'true'
});
// Send initial message
res.write('data: {"status":"connected"}\n\n');
// Add client to appropriate set
const clientSet = type === 'import' ? importClients :
type === 'update' ? updateClients :
type === 'reset' ? resetClients :
type === 'reset-metrics' ? resetMetricsClients :
null;
if (clientSet) {
clientSet.add(res);
// Remove client when connection closes
req.on('close', () => {
clientSet.delete(res);
});
}
};
// Update the status endpoint to include reset-metrics
app.get('/csv/status', (req, res) => {
res.json({
active: !!currentOperation,
type: currentOperation?.type || null,
progress: currentOperation ? {
status: currentOperation.status,
operation: currentOperation.operation,
current: currentOperation.current,
total: currentOperation.total,
percentage: currentOperation.percentage
} : null
});
});
// Update progress endpoint mapping
app.get('/csv/:type/progress', (req, res) => {
const { type } = req.params;
if (!['import', 'update', 'reset', 'reset-metrics'].includes(type)) {
res.status(400).json({ error: 'Invalid operation type' });
return;
}
setupSSE(req, res);
});
// Update the cancel endpoint to handle reset-metrics
app.post('/csv/cancel', (req, res) => {
const { operation } = req.query;
if (!currentOperation) {
res.status(400).json({ error: 'No operation in progress' });
return;
}
if (operation && operation.toLowerCase() !== currentOperation.type) {
res.status(400).json({ error: 'Operation type mismatch' });
return;
}
try {
// Handle cancellation based on operation type
if (currentOperation.type === 'reset-metrics') {
// Reset metrics doesn't need special cleanup
currentOperation = null;
res.json({ message: 'Reset metrics cancelled' });
} else {
// ... existing cancellation logic for other operations ...
}
} catch (error) {
console.error('Error during cancellation:', error);
res.status(500).json({ error: 'Failed to cancel operation' });
}
});
const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
console.log(`[Server] Running in ${process.env.NODE_ENV || 'development'} mode on port ${PORT}`);