import Proxy from './container/Proxy.js' import Server from './Server.js' import { RouterConfig } from '../Router.js' /** * Represents a server container that extends the Server class and handles serverless events. */ export default class ContainerServer extends Server { /** * The proxy object used for handling requests and responses. * @type {Proxy} * @protected */ protected readonly proxy: Proxy /** * Constructs a new instance of the Router class. * @param {RouterConfig} config - The configuration object for the router. * @returns None */ constructor(config: RouterConfig) { super(config) this.proxy = new Proxy(config, this.handleServerlessEvent.bind(this)) this.listenProcessEvents() } /** * Returns a callable function that can be used to export data. * @returns {CallableFunction} - A callable function that can be used to export data. */ public getExport(): CallableFunction { // start server socket this.start() // return empty function, we are all done return () => {} } /** * Starts the application by loading the proxy. * @returns {Promise} - A promise that resolves when the proxy is loaded. */ public async start() { try { console.log('[ContainerServer] Starting server...') await this.proxy.load() console.log('[ContainerServer] Server started successfully') } catch (error) { console.error('[ContainerServer] Failed to start server:', error) throw error } } /** * Stops the execution of the program and unloads the proxy. * @param {any} [err] - Optional error object to pass to the unload method. * @returns {Promise} - A promise that resolves once the proxy is unloaded. */ public async stop(err?: any) { try { console.log('[ContainerServer] Stopping server...') await this.proxy.unload(err) console.log('[ContainerServer] Server stopped successfully') } catch (stopError) { console.error('[ContainerServer] Error during server shutdown:', stopError) // Force exit if graceful shutdown fails process.exit(1) } } /** * Listens for process events and handles them accordingly. * @private * @returns None */ private listenProcessEvents() { // Handle unhandled promise rejections process.on('unhandledRejection', (reason, promise) => { console.error('[ContainerServer] CRITICAL: Unhandled Promise Rejection') console.error('[ContainerServer] Reason:', reason) if (reason instanceof Error) { console.error('[ContainerServer] Stack:', reason.stack) } console.error('[ContainerServer] Promise:', promise) console.error('[ContainerServer] Shutting down server due to unhandled rejection...') this.stop(reason) }) // Handle uncaught exceptions process.on('uncaughtException', error => { console.error('[ContainerServer] CRITICAL: Uncaught Exception') console.error('[ContainerServer] Error:', error) console.error('[ContainerServer] Stack:', error.stack) console.error('[ContainerServer] Shutting down server due to uncaught exception...') this.stop(error) }) // Handle SIGINT (Ctrl+C) process.on('SIGINT', () => { console.log('[ContainerServer] SIGINT received, shutting down gracefully...') this.stop() }) // Handle SIGTERM (Docker/ECS stop) process.on('SIGTERM', () => { console.log('[ContainerServer] SIGTERM received, shutting down gracefully...') this.stop() }) // Log when process is about to exit process.on('exit', code => { console.log(`[ContainerServer] 🚪 Process exiting with code: ${code}`) }) } }