@morojs/moro 1.5.5 → 1.5.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (70) hide show
  1. package/dist/core/config/config-manager.d.ts +44 -0
  2. package/dist/core/config/config-manager.js +114 -0
  3. package/dist/core/config/config-manager.js.map +1 -0
  4. package/dist/core/config/config-sources.d.ts +21 -0
  5. package/dist/core/config/config-sources.js +314 -0
  6. package/dist/core/config/config-sources.js.map +1 -0
  7. package/dist/core/config/config-validator.d.ts +21 -0
  8. package/dist/core/config/config-validator.js +744 -0
  9. package/dist/core/config/config-validator.js.map +1 -0
  10. package/dist/core/config/file-loader.d.ts +0 -5
  11. package/dist/core/config/file-loader.js +0 -171
  12. package/dist/core/config/file-loader.js.map +1 -1
  13. package/dist/core/config/index.d.ts +39 -10
  14. package/dist/core/config/index.js +66 -29
  15. package/dist/core/config/index.js.map +1 -1
  16. package/dist/core/config/schema.js +29 -31
  17. package/dist/core/config/schema.js.map +1 -1
  18. package/dist/core/config/utils.d.ts +9 -2
  19. package/dist/core/config/utils.js +19 -32
  20. package/dist/core/config/utils.js.map +1 -1
  21. package/dist/core/framework.d.ts +4 -7
  22. package/dist/core/framework.js +38 -12
  23. package/dist/core/framework.js.map +1 -1
  24. package/dist/core/http/http-server.d.ts +12 -0
  25. package/dist/core/http/http-server.js +56 -0
  26. package/dist/core/http/http-server.js.map +1 -1
  27. package/dist/core/http/router.d.ts +12 -0
  28. package/dist/core/http/router.js +114 -36
  29. package/dist/core/http/router.js.map +1 -1
  30. package/dist/core/logger/index.d.ts +1 -1
  31. package/dist/core/logger/index.js +2 -1
  32. package/dist/core/logger/index.js.map +1 -1
  33. package/dist/core/logger/logger.d.ts +9 -1
  34. package/dist/core/logger/logger.js +36 -3
  35. package/dist/core/logger/logger.js.map +1 -1
  36. package/dist/core/routing/index.d.ts +20 -0
  37. package/dist/core/routing/index.js +109 -11
  38. package/dist/core/routing/index.js.map +1 -1
  39. package/dist/moro.d.ts +7 -20
  40. package/dist/moro.js +115 -200
  41. package/dist/moro.js.map +1 -1
  42. package/dist/types/config.d.ts +46 -2
  43. package/dist/types/core.d.ts +22 -39
  44. package/dist/types/logger.d.ts +4 -0
  45. package/package.json +1 -1
  46. package/src/core/config/config-manager.ts +133 -0
  47. package/src/core/config/config-sources.ts +384 -0
  48. package/src/core/config/config-validator.ts +1042 -0
  49. package/src/core/config/file-loader.ts +0 -233
  50. package/src/core/config/index.ts +77 -32
  51. package/src/core/config/schema.ts +29 -31
  52. package/src/core/config/utils.ts +22 -29
  53. package/src/core/framework.ts +51 -18
  54. package/src/core/http/http-server.ts +66 -0
  55. package/src/core/http/router.ts +127 -38
  56. package/src/core/logger/index.ts +1 -0
  57. package/src/core/logger/logger.ts +43 -4
  58. package/src/core/routing/index.ts +116 -12
  59. package/src/moro.ts +127 -233
  60. package/src/types/config.ts +47 -2
  61. package/src/types/core.ts +32 -43
  62. package/src/types/logger.ts +6 -0
  63. package/dist/core/config/loader.d.ts +0 -7
  64. package/dist/core/config/loader.js +0 -269
  65. package/dist/core/config/loader.js.map +0 -1
  66. package/dist/core/config/validation.d.ts +0 -17
  67. package/dist/core/config/validation.js +0 -131
  68. package/dist/core/config/validation.js.map +0 -1
  69. package/src/core/config/loader.ts +0 -633
  70. package/src/core/config/validation.ts +0 -140
package/src/moro.ts CHANGED
@@ -11,6 +11,7 @@ import {
11
11
  logger as globalLogger,
12
12
  applyLoggingConfiguration,
13
13
  } from './core/logger';
14
+ import { Logger } from './types/logger';
14
15
  import { MiddlewareManager } from './core/middleware';
15
16
  import { IntelligentRoutingManager } from './core/routing/app-integration';
16
17
  import { RouteBuilder, RouteSchema, CompiledRoute } from './core/routing';
@@ -19,7 +20,12 @@ import { readdirSync, statSync } from 'fs';
19
20
  import { join } from 'path';
20
21
  import { EventEmitter } from 'events';
21
22
  // Configuration System Integration
22
- import { initializeConfig, getGlobalConfig, type AppConfig } from './core/config';
23
+ import {
24
+ initializeConfig,
25
+ getGlobalConfig,
26
+ loadConfigWithOptions,
27
+ type AppConfig,
28
+ } from './core/config';
23
29
  // Runtime System Integration
24
30
  import {
25
31
  RuntimeAdapter,
@@ -37,7 +43,7 @@ export class Moro extends EventEmitter {
37
43
  // Enterprise event system integration
38
44
  private eventBus: MoroEventBus;
39
45
  // Application logger
40
- private logger = createFrameworkLogger('App');
46
+ private logger!: Logger;
41
47
  // Intelligent routing system
42
48
  private intelligentRouting = new IntelligentRoutingManager();
43
49
  // Documentation system
@@ -53,72 +59,33 @@ export class Moro extends EventEmitter {
53
59
  constructor(options: MoroOptions = {}) {
54
60
  super(); // Call EventEmitter constructor
55
61
 
56
- // Configure logger from environment variables BEFORE config system initialization
57
- // This ensures the config loading process respects the log level
62
+ // Apply logging configuration BEFORE config loading to avoid DEBUG spam
63
+ // 1. Environment variables (base level)
58
64
  const envLogLevel = process.env.LOG_LEVEL || process.env.MORO_LOG_LEVEL;
59
65
  if (envLogLevel) {
60
66
  applyLoggingConfiguration({ level: envLogLevel }, undefined);
61
67
  }
62
68
 
63
- // Initialize configuration system - create a deep copy for this instance
64
- this.config = JSON.parse(JSON.stringify(initializeConfig()));
65
-
66
- // Apply logging configuration from the loaded config (this happens after config file processing)
67
- if (this.config.logging) {
68
- applyLoggingConfiguration(this.config.logging, undefined);
69
- }
70
-
71
- // Apply additional logging configuration from createApp options (takes precedence)
69
+ // 2. createApp logger options (highest precedence)
72
70
  if (options.logger !== undefined) {
73
71
  applyLoggingConfiguration(undefined, options.logger);
74
72
  }
75
73
 
76
- // Apply performance configuration from createApp options (takes precedence)
77
- if (options.performance) {
78
- if (options.performance.clustering) {
79
- this.config.performance.clustering = {
80
- ...this.config.performance.clustering,
81
- ...options.performance.clustering,
82
- };
83
- }
84
- if (options.performance.compression) {
85
- this.config.performance.compression = {
86
- ...this.config.performance.compression,
87
- ...options.performance.compression,
88
- };
89
- }
90
- if (options.performance.circuitBreaker) {
91
- this.config.performance.circuitBreaker = {
92
- ...this.config.performance.circuitBreaker,
93
- ...options.performance.circuitBreaker,
94
- };
95
- }
96
- }
74
+ // Create logger AFTER initial configuration
75
+ this.logger = createFrameworkLogger('App');
97
76
 
98
- // Apply modules configuration from createApp options (takes precedence)
99
- if (options.modules) {
100
- if (options.modules.cache) {
101
- this.config.modules.cache = {
102
- ...this.config.modules.cache,
103
- ...options.modules.cache,
104
- };
105
- }
106
- if (options.modules.rateLimit) {
107
- this.config.modules.rateLimit = {
108
- ...this.config.modules.rateLimit,
109
- ...options.modules.rateLimit,
110
- };
111
- }
112
- if (options.modules.validation) {
113
- this.config.modules.validation = {
114
- ...this.config.modules.validation,
115
- ...options.modules.validation,
116
- };
117
- }
77
+ // Use simplified global configuration system
78
+ this.config = initializeConfig(options);
79
+
80
+ // Apply config file logging if it exists (may override createApp options if needed)
81
+ if (this.config.logging && !options.logger) {
82
+ applyLoggingConfiguration(this.config.logging, undefined);
83
+ // Recreate logger with updated config
84
+ this.logger = createFrameworkLogger('App');
118
85
  }
119
86
 
120
87
  this.logger.info(
121
- `Configuration system initialized: ${this.config.server.environment}:${this.config.server.port}`
88
+ `Configuration system initialized: ${process.env.NODE_ENV || 'development'}:${this.config.server.port}`
122
89
  );
123
90
 
124
91
  // Initialize runtime system
@@ -127,10 +94,12 @@ export class Moro extends EventEmitter {
127
94
 
128
95
  this.logger.info(`Runtime system initialized: ${this.runtimeType}`, 'Runtime');
129
96
 
130
- // Pass logging configuration from config to framework
97
+ // Pass configuration from config to framework
131
98
  const frameworkOptions: any = {
132
99
  ...options,
133
100
  logger: this.config.logging,
101
+ websocket: this.config.websocket.enabled ? options.websocket || {} : false,
102
+ config: this.config,
134
103
  };
135
104
 
136
105
  this.coreFramework = new MoroCore(frameworkOptions);
@@ -540,8 +509,9 @@ export class Moro extends EventEmitter {
540
509
  this.logger.info('Moro Server Started', 'Server');
541
510
  this.logger.info(`Runtime: ${this.runtimeType}`, 'Server');
542
511
  this.logger.info(`HTTP API: http://${displayHost}:${port}`, 'Server');
543
- this.logger.info(`WebSocket: ws://${displayHost}:${port}`, 'Server');
544
- this.logger.info('Native Node.js HTTP • Zero Dependencies • Maximum Performance', 'Server');
512
+ if (this.config.websocket.enabled) {
513
+ this.logger.info(`WebSocket: ws://${displayHost}:${port}`, 'Server');
514
+ }
545
515
  this.logger.info('Learn more at https://morojs.com', 'Server');
546
516
 
547
517
  // Log intelligent routes info
@@ -886,20 +856,33 @@ export class Moro extends EventEmitter {
886
856
  }
887
857
 
888
858
  private setupDefaultMiddleware(options: MoroOptions) {
889
- // CORS
890
- if (options.cors !== false) {
891
- const corsOptions = typeof options.cors === 'object' ? options.cors : {};
859
+ // CORS - check config enabled property OR options.security.cors.enabled === true
860
+ if (this.config.security.cors.enabled || options.security?.cors?.enabled === true) {
861
+ const corsOptions =
862
+ typeof options.cors === 'object'
863
+ ? options.cors
864
+ : this.config.security.cors
865
+ ? this.config.security.cors
866
+ : {};
892
867
  this.use(middleware.cors(corsOptions));
893
868
  }
894
869
 
895
- // Helmet
896
- if (options.helmet !== false) {
870
+ // Helmet - check config enabled property OR options.security.helmet.enabled === true
871
+ if (this.config.security.helmet.enabled || options.security?.helmet?.enabled === true) {
897
872
  this.use(middleware.helmet());
898
873
  }
899
874
 
900
- // Compression
901
- if (options.compression !== false) {
902
- const compressionOptions = typeof options.compression === 'object' ? options.compression : {};
875
+ // Compression - check config enabled property OR options.performance.compression.enabled === true
876
+ if (
877
+ this.config.performance.compression.enabled ||
878
+ options.performance?.compression?.enabled === true
879
+ ) {
880
+ const compressionOptions =
881
+ typeof options.compression === 'object'
882
+ ? options.compression
883
+ : this.config.performance.compression
884
+ ? this.config.performance.compression
885
+ : {};
903
886
  this.use(middleware.compression(compressionOptions));
904
887
  }
905
888
 
@@ -936,14 +919,8 @@ export class Moro extends EventEmitter {
936
919
  }
937
920
 
938
921
  /**
939
- * Node.js Clustering Implementation with Empirical Optimizations
940
- *
941
- * This clustering algorithm is based on empirical testing and Node.js best practices.
942
- * Key findings from research and testing:
943
- *
944
- * Performance Benefits:
945
- * - Clustering can improve performance by up to 66% (Source: Medium - Danish Siddiq)
946
- * - Enables utilization of multiple CPU cores in Node.js applications
922
+ * Node.js Clustering Implementation
923
+ * This clustering algorithm is based on published research and Node.js best practices.
947
924
  *
948
925
  * IPC (Inter-Process Communication) Considerations:
949
926
  * - Excessive workers create IPC bottlenecks (Source: BetterStack Node.js Guide)
@@ -954,71 +931,53 @@ export class Moro extends EventEmitter {
954
931
  * - ~2GB per worker prevents memory pressure and GC overhead
955
932
  * - Conservative heap limits reduce memory fragmentation
956
933
  *
957
- * Empirical Findings (MoroJS Testing):
958
- * - 4-worker cap provides optimal performance regardless of core count
959
- * - IPC becomes the primary bottleneck on high-core machines (16+ cores)
960
- * - Memory allocation per worker more important than CPU utilization
961
- *
962
934
  * References:
963
935
  * - Node.js Cluster Documentation: https://nodejs.org/api/cluster.html
964
936
  * - BetterStack Node.js Clustering: https://betterstack.com/community/guides/scaling-nodejs/node-clustering/
965
937
  */
966
938
  private clusterWorkers = new Map<number, any>();
967
- private workerStats = new Map<
968
- number,
969
- { cpu: number; memory: number; requests: number; lastCheck: number }
970
- >();
971
- private adaptiveScalingEnabled = true;
972
- private lastScalingCheck = 0;
973
- private readonly SCALING_INTERVAL = 30000; // 30 seconds
974
939
 
975
940
  private startWithClustering(port: number, host?: string, callback?: () => void): void {
976
941
  const cluster = require('cluster');
977
942
  const os = require('os');
978
943
 
979
- // Smart worker count calculation to prevent IPC bottlenecks and optimize resource usage
980
- // Based on empirical testing and Node.js clustering best practices
944
+ // Worker count calculation - respect user choice
981
945
  let workerCount = this.config.performance?.clustering?.workers || os.cpus().length;
982
946
 
983
- // Auto-optimize worker count based on system characteristics
984
- // Research shows clustering can improve performance by up to 66% but excessive workers
985
- // cause IPC overhead that degrades performance (Source: Medium - Clustering in Node.js)
986
- if (workerCount === 'auto' || workerCount > 8) {
947
+ // Only auto-optimize if user hasn't specified a number or set it to 'auto'
948
+ if (workerCount === 'auto') {
987
949
  const cpuCount = os.cpus().length;
988
950
  const totalMemoryGB = os.totalmem() / (1024 * 1024 * 1024);
989
951
 
990
- // Improved worker count optimization based on research findings
991
- // Algorithm considers CPU, memory, and IPC overhead holistically
992
- const memoryPerWorkerGB = 1.5; // Optimal based on GC performance testing
993
- const maxWorkersFromMemory = Math.floor(totalMemoryGB / memoryPerWorkerGB);
994
- if (cpuCount >= 16) {
995
- // High-core machines: IPC saturation point reached quickly
996
- // Research shows diminishing returns after 4 workers due to message passing
997
- workerCount = Math.min(maxWorkersFromMemory, 4);
998
- } else if (cpuCount >= 8) {
999
- // Mid-range machines: optimal ratio found to be CPU/3 for IPC efficiency
1000
- // Avoids context switching overhead while maintaining throughput
1001
- workerCount = Math.min(Math.ceil(cpuCount / 3), maxWorkersFromMemory, 6);
1002
- } else if (cpuCount >= 4) {
1003
- // Standard machines: use 3/4 of cores to leave room for OS processes
1004
- workerCount = Math.min(Math.ceil(cpuCount * 0.75), maxWorkersFromMemory, 4);
1005
- } else {
1006
- // Low-core machines: use all cores but cap for memory safety
1007
- workerCount = Math.min(cpuCount, maxWorkersFromMemory, 2);
952
+ // Get memory per worker from config - if not set by user, calculate dynamically
953
+ let memoryPerWorkerGB = this.config.performance?.clustering?.memoryPerWorkerGB;
954
+
955
+ if (!memoryPerWorkerGB) {
956
+ // Dynamic calculation: (Total RAM - 4GB headroom) / CPU cores
957
+ const headroomGB = 4;
958
+ memoryPerWorkerGB = Math.max(0.5, Math.floor((totalMemoryGB - headroomGB) / cpuCount));
1008
959
  }
1009
960
 
1010
- this.logger.info(
1011
- `Auto-optimized workers: ${workerCount} (CPU: ${cpuCount}, RAM: ${totalMemoryGB.toFixed(1)}GB)`,
1012
- 'Cluster'
961
+ // Conservative formula based on general guidelines:
962
+ // - Don't exceed CPU cores
963
+ // - Respect user's memory allocation preference
964
+ // - Let the system resources determine the limit
965
+ workerCount = Math.min(
966
+ cpuCount, // Don't exceed CPU cores
967
+ Math.floor(totalMemoryGB / memoryPerWorkerGB) // User-configurable memory per worker
1013
968
  );
1014
- this.logger.debug(
1015
- `Worker optimization strategy: ${cpuCount >= 16 ? 'IPC-limited' : cpuCount >= 8 ? 'balanced' : 'CPU-bound'}`,
969
+
970
+ this.logger.info(
971
+ `Auto-calculated worker count: ${workerCount} (CPU: ${cpuCount}, RAM: ${totalMemoryGB.toFixed(1)}GB, ${memoryPerWorkerGB}GB per worker)`,
1016
972
  'Cluster'
1017
973
  );
974
+ } else if (typeof workerCount === 'number') {
975
+ // User specified a number - respect their choice
976
+ this.logger.info(`Using user-specified worker count: ${workerCount}`, 'Cluster');
1018
977
  }
1019
978
 
1020
979
  if (cluster.isPrimary) {
1021
- this.logger.info(`🚀 Starting ${workerCount} workers for maximum performance`, 'Cluster');
980
+ this.logger.info(`Starting ${workerCount} workers`, 'Cluster');
1022
981
 
1023
982
  // Optimize cluster scheduling for high concurrency
1024
983
  // Round-robin is the default on all platforms except Windows (Node.js docs)
@@ -1027,7 +986,7 @@ export class Moro extends EventEmitter {
1027
986
 
1028
987
  // Set cluster settings for better performance
1029
988
  cluster.setupMaster({
1030
- exec: process.argv[1],
989
+ exec: process.argv[1] || process.execPath,
1031
990
  args: process.argv.slice(2),
1032
991
  silent: false,
1033
992
  });
@@ -1057,50 +1016,34 @@ export class Moro extends EventEmitter {
1057
1016
  process.on('SIGINT', gracefulShutdown);
1058
1017
  process.on('SIGTERM', gracefulShutdown);
1059
1018
 
1060
- // Fork workers with proper tracking and CPU affinity
1019
+ // Fork workers with basic tracking
1061
1020
  for (let i = 0; i < workerCount; i++) {
1062
- const worker = cluster.fork({
1063
- WORKER_ID: i,
1064
- WORKER_CPU_AFFINITY: i % os.cpus().length, // Distribute workers across CPUs
1065
- });
1021
+ const worker = cluster.fork();
1066
1022
  this.clusterWorkers.set(worker.process.pid!, worker);
1067
- this.logger.info(
1068
- `Worker ${worker.process.pid} started (CPU ${i % os.cpus().length})`,
1069
- 'Cluster'
1070
- );
1023
+ this.logger.info(`Worker ${worker.process.pid} started`, 'Cluster');
1071
1024
 
1072
- // Handle individual worker messages (reuse handler)
1025
+ // Handle individual worker messages
1073
1026
  worker.on('message', this.handleWorkerMessage.bind(this));
1074
1027
  }
1075
1028
 
1076
- // Enhanced worker exit handling with adaptive monitoring
1029
+ // Simple worker exit handling
1077
1030
  cluster.on('exit', (worker: any, code: number, signal: string) => {
1078
1031
  const pid = worker.process.pid;
1079
-
1080
- // Clean up worker tracking and stats
1081
1032
  this.clusterWorkers.delete(pid);
1082
- this.workerStats.delete(pid);
1083
1033
 
1084
1034
  if (code !== 0 && !worker.exitedAfterDisconnect) {
1085
1035
  this.logger.warn(
1086
- `Worker ${pid} died unexpectedly (${signal || code}). Analyzing performance...`,
1036
+ `Worker ${pid} died unexpectedly (${signal || code}). Restarting...`,
1087
1037
  'Cluster'
1088
1038
  );
1089
1039
 
1090
- // Check if we should scale workers based on performance
1091
- this.evaluateWorkerPerformance();
1040
+ // Simple restart
1041
+ const newWorker = cluster.fork();
1042
+ this.clusterWorkers.set(newWorker.process.pid!, newWorker);
1043
+ this.logger.info(`Worker ${newWorker.process.pid} restarted`, 'Cluster');
1092
1044
  }
1093
-
1094
- // Restart worker with enhanced tracking
1095
- const newWorker = this.forkWorkerWithMonitoring();
1096
- this.logger.info(`Worker ${newWorker.process.pid} started with monitoring`, 'Cluster');
1097
1045
  });
1098
1046
 
1099
- // Start adaptive scaling system
1100
- if (this.adaptiveScalingEnabled) {
1101
- this.startAdaptiveScaling();
1102
- }
1103
-
1104
1047
  // Master process callback
1105
1048
  if (callback) callback();
1106
1049
  } else {
@@ -1114,25 +1057,24 @@ export class Moro extends EventEmitter {
1114
1057
  // Multiple workers writing to same log files creates I/O contention
1115
1058
  if (this.config.logging) {
1116
1059
  // Workers log less frequently to reduce I/O contention
1117
- this.config.logging.level = 'warn'; // Only warnings and errors
1060
+ applyLoggingConfiguration(undefined, { level: 'warn' }); // Only warnings and errors
1118
1061
  }
1119
1062
 
1120
- // Enhanced memory optimization for workers
1121
- // Dynamic heap sizing based on available system memory and worker count
1063
+ // Research-based memory optimization for workers
1122
1064
  const os = require('os');
1123
1065
  const totalMemoryGB = os.totalmem() / (1024 * 1024 * 1024);
1124
1066
  const workerCount = Object.keys(require('cluster').workers || {}).length || 1;
1125
1067
 
1126
- // Allocate memory more intelligently based on system resources
1068
+ // Conservative memory allocation
1127
1069
  const heapSizePerWorkerMB = Math.min(
1128
- Math.floor((totalMemoryGB * 1024) / (workerCount * 1.5)), // Leave buffer for OS
1129
- 1536 // Cap at 1.5GB per worker to prevent excessive GC
1070
+ Math.floor(((totalMemoryGB * 1024) / workerCount) * 0.8), // 80% of available memory
1071
+ 1536 // Cap at 1.5GB (GC efficiency threshold from research)
1130
1072
  );
1131
1073
 
1132
1074
  process.env.NODE_OPTIONS = `--max-old-space-size=${heapSizePerWorkerMB}`;
1133
1075
 
1134
1076
  this.logger.debug(
1135
- `Worker memory optimized: ${heapSizePerWorkerMB}MB heap (${workerCount} workers, ${totalMemoryGB.toFixed(1)}GB total)`,
1077
+ `Worker memory allocated: ${heapSizePerWorkerMB}MB heap (${workerCount} workers, ${totalMemoryGB.toFixed(1)}GB total)`,
1136
1078
  'Worker'
1137
1079
  );
1138
1080
 
@@ -1230,20 +1172,8 @@ export class Moro extends EventEmitter {
1230
1172
  }
1231
1173
  }
1232
1174
 
1233
- // Enhanced worker message handler with performance monitoring
1175
+ // Simple worker message handler
1234
1176
  private handleWorkerMessage(message: any): void {
1235
- // Handle performance monitoring messages
1236
- if (message.type === 'performance') {
1237
- const pid = message.pid;
1238
- this.workerStats.set(pid, {
1239
- cpu: message.cpu || 0,
1240
- memory: message.memory || 0,
1241
- requests: message.requests || 0,
1242
- lastCheck: Date.now(),
1243
- });
1244
- return;
1245
- }
1246
-
1247
1177
  // Handle inter-worker communication if needed
1248
1178
  if (message.type === 'health-check') {
1249
1179
  // Worker health check response
@@ -1254,83 +1184,47 @@ export class Moro extends EventEmitter {
1254
1184
  this.logger.debug(`Worker message: ${JSON.stringify(message)}`, 'Cluster');
1255
1185
  }
1256
1186
 
1257
- private forkWorkerWithMonitoring(): any {
1258
- const cluster = require('cluster');
1259
- const os = require('os');
1260
-
1261
- const worker = cluster.fork({
1262
- WORKER_ID: this.clusterWorkers.size,
1263
- WORKER_CPU_AFFINITY: this.clusterWorkers.size % os.cpus().length,
1264
- });
1265
-
1266
- this.clusterWorkers.set(worker.process.pid!, worker);
1267
- worker.on('message', this.handleWorkerMessage.bind(this));
1268
-
1269
- return worker;
1270
- }
1187
+ /**
1188
+ * Gracefully close the application and clean up resources
1189
+ * This should be called in tests and during shutdown
1190
+ */
1191
+ async close(): Promise<void> {
1192
+ this.logger.debug('Closing Moro application...');
1271
1193
 
1272
- private evaluateWorkerPerformance(): void {
1273
- const now = Date.now();
1274
- const currentWorkerCount = this.clusterWorkers.size;
1275
-
1276
- // Calculate average CPU and memory usage across workers
1277
- let totalCpu = 0;
1278
- let totalMemory = 0;
1279
- let activeWorkers = 0;
1280
-
1281
- for (const [pid, stats] of this.workerStats) {
1282
- if (now - stats.lastCheck < 60000) {
1283
- // Data less than 1 minute old
1284
- totalCpu += stats.cpu;
1285
- totalMemory += stats.memory;
1286
- activeWorkers++;
1287
- }
1194
+ // Flush logger buffer before shutdown
1195
+ try {
1196
+ // Use flushBuffer for immediate synchronous flush
1197
+ this.logger.flushBuffer();
1198
+ } catch (error) {
1199
+ // Ignore flush errors during shutdown
1288
1200
  }
1289
1201
 
1290
- if (activeWorkers === 0) return;
1291
-
1292
- const avgCpu = totalCpu / activeWorkers;
1293
- const avgMemory = totalMemory / activeWorkers;
1294
-
1295
- this.logger.debug(
1296
- `Performance analysis: ${activeWorkers} workers, avg CPU: ${avgCpu.toFixed(1)}%, avg memory: ${avgMemory.toFixed(1)}MB`,
1297
- 'Cluster'
1298
- );
1299
-
1300
- // Research-based adaptive scaling decisions
1301
- // High CPU threshold indicates IPC saturation point approaching
1302
- if (avgCpu > 80 && currentWorkerCount < 6) {
1303
- this.logger.info(
1304
- 'High CPU load detected, system may benefit from additional worker',
1305
- 'Cluster'
1306
- );
1307
- } else if (avgCpu < 25 && currentWorkerCount > 2) {
1308
- this.logger.info(
1309
- 'Low CPU utilization detected, excessive workers may be causing IPC overhead',
1310
- 'Cluster'
1311
- );
1202
+ // Close the core framework with timeout
1203
+ if (this.coreFramework && (this.coreFramework as any).httpServer) {
1204
+ try {
1205
+ await Promise.race([
1206
+ new Promise<void>(resolve => {
1207
+ (this.coreFramework as any).httpServer.close(() => {
1208
+ resolve();
1209
+ });
1210
+ }),
1211
+ new Promise<void>(resolve => setTimeout(resolve, 2000)), // 2 second timeout
1212
+ ]);
1213
+ } catch (error) {
1214
+ // Force close if graceful close fails
1215
+ this.logger.warn('Force closing HTTP server due to timeout');
1216
+ }
1312
1217
  }
1313
1218
 
1314
- // Memory pressure monitoring
1315
- if (avgMemory > 1200) {
1316
- // MB
1317
- this.logger.warn(
1318
- 'High memory usage per worker detected, may need worker restart or scaling adjustment',
1319
- 'Cluster'
1320
- );
1219
+ // Clean up event listeners
1220
+ try {
1221
+ this.eventBus.removeAllListeners();
1222
+ this.removeAllListeners();
1223
+ } catch (error) {
1224
+ // Ignore cleanup errors
1321
1225
  }
1322
- }
1323
-
1324
- private startAdaptiveScaling(): void {
1325
- setInterval(() => {
1326
- const now = Date.now();
1327
- if (now - this.lastScalingCheck > this.SCALING_INTERVAL) {
1328
- this.evaluateWorkerPerformance();
1329
- this.lastScalingCheck = now;
1330
- }
1331
- }, this.SCALING_INTERVAL);
1332
1226
 
1333
- this.logger.info('Adaptive performance monitoring system started', 'Cluster');
1227
+ this.logger.debug('Moro application closed successfully');
1334
1228
  }
1335
1229
  }
1336
1230
 
@@ -3,9 +3,15 @@
3
3
  export interface ServerConfig {
4
4
  port: number;
5
5
  host: string;
6
- environment: 'development' | 'staging' | 'production';
7
6
  maxConnections: number;
8
7
  timeout: number;
8
+ bodySizeLimit: string;
9
+ requestTracking: {
10
+ enabled: boolean;
11
+ };
12
+ errorBoundary: {
13
+ enabled: boolean;
14
+ };
9
15
  }
10
16
 
11
17
  export interface ServiceDiscoveryConfig {
@@ -19,7 +25,7 @@ export interface ServiceDiscoveryConfig {
19
25
 
20
26
  export interface DatabaseConfig {
21
27
  url?: string;
22
- redis: {
28
+ redis?: {
23
29
  url: string;
24
30
  maxRetries: number;
25
31
  retryDelay: number;
@@ -35,6 +41,28 @@ export interface DatabaseConfig {
35
41
  acquireTimeout: number;
36
42
  timeout: number;
37
43
  };
44
+ postgresql?: {
45
+ host: string;
46
+ port: number;
47
+ database?: string;
48
+ user?: string;
49
+ password?: string;
50
+ connectionLimit: number;
51
+ ssl?: boolean;
52
+ };
53
+ sqlite?: {
54
+ filename: string;
55
+ memory?: boolean;
56
+ verbose?: boolean;
57
+ };
58
+ mongodb?: {
59
+ url?: string;
60
+ host?: string;
61
+ port?: number;
62
+ database?: string;
63
+ username?: string;
64
+ password?: string;
65
+ };
38
66
  }
39
67
 
40
68
  export interface ModuleDefaultsConfig {
@@ -141,6 +169,22 @@ export interface PerformanceConfig {
141
169
  clustering: {
142
170
  enabled: boolean;
143
171
  workers: number | 'auto';
172
+ memoryPerWorkerGB?: number;
173
+ };
174
+ }
175
+
176
+ export interface WebSocketConfig {
177
+ enabled: boolean;
178
+ adapter?: string | 'socket.io' | 'ws';
179
+ compression?: boolean;
180
+ customIdGenerator?: () => string;
181
+ options?: {
182
+ cors?: {
183
+ origin?: string | string[];
184
+ credentials?: boolean;
185
+ };
186
+ path?: string;
187
+ maxPayloadLength?: number;
144
188
  };
145
189
  }
146
190
 
@@ -154,4 +198,5 @@ export interface AppConfig {
154
198
  security: SecurityConfig;
155
199
  external: ExternalServicesConfig;
156
200
  performance: PerformanceConfig;
201
+ websocket: WebSocketConfig;
157
202
  }