Dataforth DOS: - TestDataDB: singleton DB connection fix (crash prevention), WAL mode, WinSW service config, backup script, uncaught exception handlers - Sync-FromNAS.ps1: Get-NASFileList temp file approach to avoid SSH stdout deadlock, *> $null output suppression, 8.3 filename filter for PUSH phase, backslash-escaped SCP paths, rename-to-.synced - import.js: INSERT OR REPLACE for re-tested devices - Full import run: 1,028,275 -> 1,632,793 records, indexes added - Deploy script for sync fixes to AD2 Client scripts (temp/): - BG Builders: Lesley account check, MFA phone update - Lonestar Electrical: Kyla/Russ Google Workspace setup, 2FA bypass - AD2 diagnostics and NAS connectivity tests PENDING: Investigate why newest test_date is Jan 19 despite daily tests Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
104 lines
3.7 KiB
JavaScript
104 lines
3.7 KiB
JavaScript
/**
|
|
* Test Data Database Server
|
|
* Express.js server with search API and web interface
|
|
*
|
|
* Fixed version - singleton DB connection, crash resilience,
|
|
* graceful shutdown, request logging.
|
|
*/
|
|
|
|
const express = require('express');
|
|
const cors = require('cors');
|
|
const path = require('path');
|
|
|
|
const apiRoutes = require('./routes/api');
|
|
const { cleanup } = require('./routes/api');
|
|
|
|
const app = express();
|
|
const PORT = process.env.PORT || 3000;
|
|
const HOST = '0.0.0.0';
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Crash resilience - log and continue rather than dying
|
|
// ---------------------------------------------------------------------------
|
|
process.on('uncaughtException', (err) => {
|
|
console.error(`[${new Date().toISOString()}] [UNCAUGHT EXCEPTION] ${err.stack || err.message}`);
|
|
});
|
|
|
|
process.on('unhandledRejection', (reason) => {
|
|
console.error(`[${new Date().toISOString()}] [UNHANDLED REJECTION] ${reason}`);
|
|
});
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Middleware
|
|
// ---------------------------------------------------------------------------
|
|
app.use(cors());
|
|
app.use(express.json());
|
|
app.use(express.static(path.join(__dirname, 'public')));
|
|
|
|
// Request logging
|
|
app.use((req, res, next) => {
|
|
const start = Date.now();
|
|
res.on('finish', () => {
|
|
const duration = Date.now() - start;
|
|
console.log(
|
|
`[${new Date().toISOString()}] ${req.method} ${req.originalUrl} ${res.statusCode} ${duration}ms`
|
|
);
|
|
});
|
|
next();
|
|
});
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Routes
|
|
// ---------------------------------------------------------------------------
|
|
app.use('/api', apiRoutes);
|
|
|
|
// Serve index.html for root
|
|
app.get('/', (req, res) => {
|
|
res.sendFile(path.join(__dirname, 'public', 'index.html'));
|
|
});
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Start server
|
|
// ---------------------------------------------------------------------------
|
|
const server = app.listen(PORT, HOST, () => {
|
|
console.log(`\n========================================`);
|
|
console.log(`Test Data Database Server`);
|
|
console.log(`========================================`);
|
|
console.log(`Server running on all interfaces (${HOST}:${PORT})`);
|
|
console.log(`Local: http://localhost:${PORT}`);
|
|
console.log(`LAN: http://192.168.0.6:${PORT}`);
|
|
console.log(`API endpoints:`);
|
|
console.log(` GET /api/search?serial=...&model=...`);
|
|
console.log(` GET /api/record/:id`);
|
|
console.log(` GET /api/datasheet/:id`);
|
|
console.log(` GET /api/stats`);
|
|
console.log(` GET /api/filters`);
|
|
console.log(` GET /api/export?format=csv&...`);
|
|
console.log(`========================================\n`);
|
|
});
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Graceful shutdown
|
|
// ---------------------------------------------------------------------------
|
|
function shutdown(signal) {
|
|
console.log(`\n[${new Date().toISOString()}] Received ${signal}. Shutting down gracefully...`);
|
|
server.close(() => {
|
|
console.log(`[${new Date().toISOString()}] HTTP server closed.`);
|
|
cleanup();
|
|
console.log(`[${new Date().toISOString()}] Database connection closed. Goodbye.`);
|
|
process.exit(0);
|
|
});
|
|
|
|
// Force exit after 10 seconds if graceful shutdown stalls
|
|
setTimeout(() => {
|
|
console.error(`[${new Date().toISOString()}] Forced shutdown after timeout.`);
|
|
cleanup();
|
|
process.exit(1);
|
|
}, 10000);
|
|
}
|
|
|
|
process.on('SIGTERM', () => shutdown('SIGTERM'));
|
|
process.on('SIGINT', () => shutdown('SIGINT'));
|
|
|
|
module.exports = app;
|