sync: Dataforth sync fixes, TestDataDB stability, and client scripts
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>
This commit is contained in:
103
projects/dataforth-dos/testdatadb-fix/server.js
Normal file
103
projects/dataforth-dos/testdatadb-fix/server.js
Normal file
@@ -0,0 +1,103 @@
|
||||
/**
|
||||
* 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;
|
||||
Reference in New Issue
Block a user