server.js
Rama main · réplica de lectura del repositorio original.
// SPDX-License-Identifier: Apache-2.0
// Copyright 2024-present Scalytics, Inc. (https://www.scalytics.io)
// ──────────────────────────────────────────────────────────────────────────────
// Shim for all `node:`-prefixed core modules (events, buffer, etc.)
// ──────────────────────────────────────────────────────────────────────────────
const Module = require('module');
const _origLoad = Module._load;
Module._load = function(request, parent, isMain) {
// if it's something like 'node:events' or 'node:buffer', strip the prefix
if (request.startsWith('node:')) {
request = request.slice(5);
}
return _origLoad(request, parent, isMain);
};
// ──────────────────────────────────────────────────────────────────────────────
const express = require('express');
const path = require('path');
const fs = require('fs');
const http = require('http');
const dotenv = require('dotenv');
const dbPath = path.join(__dirname, 'src', 'models', 'db.js');
if (!fs.existsSync(dbPath)) {
console.error('ERROR: Database module not found at %s. Deployment issue?', dbPath);
process.exit(1);
}
const { ensureSecureKeys } = require('./src/utils/securityUtils');
const { checkHuggingFaceDependencies } = require('./scripts/check_hf_dependencies');
const { loadSystemSettings } = require('./src/config/systemConfig');
// Configure llama.cpp shared library path (if exists)
const llamaBinDir = path.join(__dirname, 'bin', 'llama');
if (fs.existsSync(llamaBinDir)) {
process.env.LD_LIBRARY_PATH = process.env.LD_LIBRARY_PATH
? `${llamaBinDir}:${process.env.LD_LIBRARY_PATH}`
: llamaBinDir;
}
// Setup process-wide uncaught exception handlers
process.on('uncaughtException', (err) => {
console.error('\n=====================================');
console.error('UNCAUGHT EXCEPTION - SERVER CRASHING:', err);
fs.appendFileSync('server-crash.log', `\n[${new Date().toISOString()}] UNCAUGHT EXCEPTION:\n${err.stack}\n`);
process.exit(1);
});
process.on('unhandledRejection', (reason, promise) => {
console.error('\n=====================================');
console.error('UNHANDLED PROMISE REJECTION:', reason);
fs.appendFileSync('server-crash.log', `\n[${new Date().toISOString()}] UNHANDLED REJECTION:\n${reason}\n`);
});
// Load .env file but DO NOT override existing process.env variables (like those set by PM2)
dotenv.config({ override: false });
try {
ensureSecureKeys();
const app = express();
const server = http.createServer(app);
const PORT = process.env.PORT || 3000;
// Set long timeouts to prevent premature socket closure for long-running SSE streams
server.timeout = 600000; // 10 minutes
server.headersTimeout = 600000; // 10 minutes
const { initializeSocket } = require('./src/config/socket');
const wsServer = initializeSocket(server);
const { setupEventBusBridge } = require('./src/config/eventBusBridge');
setupEventBusBridge(wsServer);
app.set('wsServer', wsServer);
const { setupMiddleware, getFileUploadMiddleware } = require('./src/config/middleware');
const { protect } = require('./src/middleware/authMiddleware');
setupMiddleware(app);
const { setupRoutes } = require('./src/config/routes');
setupRoutes(app, {
fileUpload: getFileUploadMiddleware(),
protect: protect
});
app.use((err, req, res, next) => {
if (err instanceof SyntaxError && err.status === 400 && 'body' in err) {
console.error('Malformed JSON received:', err.message);
return res.status(400).json({ error: 'Malformed JSON payload.' });
}
if (err.type === 'entity.too.large' || (err.name === 'PayloadTooLargeError' || err.status === 413)) {
console.warn("PayloadTooLargeError encountered for %s %s: %s", String(req.method).replace(/\n|\r/g, ''), String(req.path).replace(/\n|\r/g, ''), err.message);
const limit = err.limit ? `${(err.limit / 1024 / 1024).toFixed(2)} MB` : 'the configured limit';
return res.status(413).json({
error: 'Request payload is too large.',
message: `The request body exceeds ${limit}.`
});
}
console.error('Unhandled Express error:', err);
if (!res.headersSent) {
res.status(err.status || 500).json({ error: 'An unexpected server error occurred.' });
}
});
async function startServer() {
try {
const { initializeServer } = require('./src/config/database');
await initializeServer();
await loadSystemSettings();
if (process.env.SKIP_HF_CHECK !== 'true') {
try {
await checkHuggingFaceDependencies();
} catch (hfError) {
console.warn('Warning: Hugging Face dependency check failed:', hfError.message);
}
}
if (process.env.SKIP_VLLM_SERVICE !== 'true') {
try {
const vllmService = require('./src/services/vllmService');
if (typeof vllmService.initialize === 'function') {
await vllmService.initialize();
}
} catch (vllmError) {
console.warn('Warning: vLLM Service initialization failed:', vllmError.message);
}
}
server.listen(PORT, () => {
});
} catch (error) {
console.error('Failed to start server:', error);
fs.appendFileSync('server-crash.log', `\n[${new Date().toISOString()}] STARTUP ERROR:\n${error.stack}\n`);
process.exit(1);
}
}
startServer();
const shutdown = (signal) => {
server.close(async () => {
try {
if (process.env.SKIP_VLLM_SERVICE !== 'true') {
const vllmService = require('./src/services/vllmService');
if (vllmService && typeof vllmService.shutdown === 'function') {
await vllmService.shutdown();
}
}
const { db } = require('./src/models/db');
if (db && typeof db.close === 'function') {
await new Promise((resolve, reject) => {
db.close((err) => {
if (err) {
console.error('Error closing database:', err.message);
reject(err);
} else {
resolve();
}
});
});
}
} catch (dbCloseError) {
console.error('Error accessing/closing database during shutdown:', dbCloseError);
}
process.exit(0);
});
setTimeout(() => {
console.error('Graceful shutdown timed out. Forcing exit.');
process.exit(1);
}, 10000);
};
process.on('SIGTERM', () => shutdown('SIGTERM'));
process.on('SIGINT', () => shutdown('SIGINT'));
} catch (initError) {
console.error('Error during server initialization:', initError);
fs.appendFileSync('server-crash.log', `\n[${new Date().toISOString()}] INITIALIZATION ERROR:\n${initError.stack}\n`);
process.exit(1);
}