run-production.ts 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400
  1. #!/usr/bin/env tsx
  2. /**
  3. * 生产环境完整交易系统启动器
  4. * Production Complete Trading System Launcher
  5. *
  6. * 基于 main-complete.ts 的生产级部署版本
  7. */
  8. import { CompleteTradingSystem } from './src/main-complete.js'
  9. import { ProductionLogger } from './src/utils/ProductionLogger.js'
  10. import * as fs from 'fs'
  11. import * as http from 'http'
  12. class ProductionSystemRunner {
  13. private system?: CompleteTradingSystem
  14. private logger: ProductionLogger
  15. private isShuttingDown = false
  16. private healthCheckServer?: http.Server
  17. private systemStartTime = Date.now()
  18. constructor() {
  19. this.logger = ProductionLogger.getInstance({
  20. level: (process.env.LOG_LEVEL as any) || 'info',
  21. enableFile: true,
  22. logDir: process.env.LOG_DIR || './logs',
  23. enableConsole: true,
  24. enableAudit: true,
  25. })
  26. }
  27. async start() {
  28. this.displayBanner()
  29. this.setupSignalHandlers()
  30. this.startHealthCheck()
  31. this.logger.info('🚀 启动生产级交易系统', {
  32. nodeEnv: process.env.NODE_ENV,
  33. pid: process.pid,
  34. memory: process.memoryUsage(),
  35. version: '1.0.0',
  36. })
  37. try {
  38. // 环境检查
  39. this.performEnvironmentCheck()
  40. // 创建并启动完整交易系统
  41. this.system = new CompleteTradingSystem()
  42. // 绑定生产环境监听器
  43. this.setupProductionEventHandlers()
  44. // 启动系统
  45. await this.system.start()
  46. this.logger.info('✅ 生产系统启动成功', {
  47. healthCheckUrl: 'http://localhost:3001/health',
  48. uptime: Date.now() - this.systemStartTime,
  49. })
  50. console.log(`
  51. ✅ 🚀 生产级交易系统已启动!
  52. 📊 监控地址:
  53. - 健康检查: http://localhost:3001/health
  54. - 系统状态: http://localhost:3001/status
  55. - 性能指标: http://localhost:3001/metrics
  56. 🔧 管理命令:
  57. - curl http://localhost:3001/health # 检查系统健康
  58. - kill -TERM ${process.pid} # 优雅关闭
  59. - kill -USR1 ${process.pid} # 重载配置
  60. 📁 日志位置: ${process.env.LOG_DIR || './logs'}
  61. `)
  62. // PM2 兼容性
  63. if (process.send) {
  64. process.send('ready')
  65. }
  66. // 保持运行并启动监控
  67. this.startSystemMonitoring()
  68. } catch (error: any) {
  69. this.logger.critical('❌ 生产系统启动失败', error)
  70. console.error('❌ 生产系统启动失败:', error.message)
  71. process.exit(1)
  72. }
  73. }
  74. private displayBanner() {
  75. console.log(`
  76. ██████ ██████ ██████ ██████ ██ ██ ██████ ████████ ██ ██████ ███ ██
  77. ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ████ ██
  78. ██████ ██████ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██
  79. ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██
  80. ██ ██ ██ ██████ ██████ ██████ ██████ ██ ██ ██████ ██ ████
  81. 🌟 生产级完整交易系统 v1.0.0
  82. 🔥 多平台对冲 | 实时监控 | 自动化交易 | 风险控制
  83. 启动时间: ${new Date().toLocaleString('zh-CN')}
  84. 进程 ID: ${process.pid}
  85. Node.js: ${process.version}
  86. 内存: ${Math.round(process.memoryUsage().rss / 1024 / 1024)}MB
  87. `)
  88. }
  89. private performEnvironmentCheck() {
  90. const required = ['NODE_ENV']
  91. const missing = required.filter(env => !process.env[env])
  92. if (missing.length > 0) {
  93. this.logger.warn('⚠️ 缺少环境变量', { missingVars: missing })
  94. }
  95. // 检查日志目录
  96. const logDir = process.env.LOG_DIR || './logs'
  97. if (!fs.existsSync(logDir)) {
  98. fs.mkdirSync(logDir, { recursive: true })
  99. this.logger.info('📁 创建日志目录', { logDir })
  100. }
  101. this.logger.info('✅ 环境检查完成', {
  102. nodeEnv: process.env.NODE_ENV,
  103. logDir,
  104. })
  105. }
  106. private startHealthCheck() {
  107. this.healthCheckServer = http.createServer((req, res) => {
  108. const url = req.url || ''
  109. // CORS 支持
  110. res.setHeader('Access-Control-Allow-Origin', '*')
  111. res.setHeader('Content-Type', 'application/json')
  112. if (url === '/health') {
  113. const health = {
  114. status: 'healthy',
  115. timestamp: new Date().toISOString(),
  116. uptime: process.uptime(),
  117. memory: process.memoryUsage(),
  118. pid: process.pid,
  119. system: this.system ? 'running' : 'starting',
  120. version: '1.0.0',
  121. }
  122. res.writeHead(200)
  123. res.end(JSON.stringify(health, null, 2))
  124. } else if (url === '/status' && this.system) {
  125. try {
  126. const stats = this.system.getSystemStats()
  127. res.writeHead(200)
  128. res.end(JSON.stringify(stats, null, 2))
  129. } catch (error: any) {
  130. res.writeHead(500)
  131. res.end(JSON.stringify({ error: error.message }))
  132. }
  133. } else if (url === '/metrics') {
  134. const metrics = {
  135. timestamp: new Date().toISOString(),
  136. uptime: process.uptime(),
  137. memory: process.memoryUsage(),
  138. cpu: process.cpuUsage(),
  139. startTime: this.systemStartTime,
  140. systemActive: !!this.system,
  141. }
  142. res.writeHead(200)
  143. res.end(JSON.stringify(metrics, null, 2))
  144. } else {
  145. res.writeHead(404)
  146. res.end(JSON.stringify({ error: 'Not Found' }))
  147. }
  148. })
  149. this.healthCheckServer.listen(3001, () => {
  150. console.log('🏥 健康检查服务器已启动: http://localhost:3001/health')
  151. })
  152. this.healthCheckServer.on('error', (error: any) => {
  153. this.logger.error('健康检查服务器错误', error)
  154. })
  155. }
  156. private setupProductionEventHandlers() {
  157. if (!this.system) return
  158. // 系统级事件
  159. this.system.on('error', (error: Error) => {
  160. this.logger.error('🚨 系统错误', error)
  161. if (error.message.includes('FATAL')) {
  162. this.logger.critical('💀 致命错误,准备重启', error)
  163. this.attemptSystemRestart()
  164. }
  165. })
  166. this.system.on('warning', (warning: string) => {
  167. this.logger.warn(`⚠️ 系统警告: ${warning}`)
  168. })
  169. // 交易事件
  170. this.system.on('trade_executed', (data: any) => {
  171. this.logger.trade('订单执行', {
  172. exchange: data.exchange,
  173. symbol: data.symbol,
  174. side: data.side,
  175. quantity: data.quantity,
  176. price: data.price,
  177. orderId: data.orderId,
  178. })
  179. })
  180. // 对冲事件
  181. this.system.on('hedge_executed', (data: any) => {
  182. this.logger.hedge('对冲执行', {
  183. sourceExchange: data.sourceExchange,
  184. targetExchange: data.targetExchange,
  185. symbol: data.symbol,
  186. quantity: data.quantity,
  187. reason: data.reason,
  188. })
  189. })
  190. }
  191. private startSystemMonitoring() {
  192. // 心跳检查 (每分钟)
  193. const heartbeatInterval = setInterval(async () => {
  194. if (this.isShuttingDown) {
  195. clearInterval(heartbeatInterval)
  196. return
  197. }
  198. try {
  199. if (this.system) {
  200. const stats = await this.system.getSystemStats()
  201. this.logger.info('💓 系统心跳', {
  202. accounts: stats.accounts.total,
  203. connections: stats.connections.active,
  204. dailyTrades: stats.trading.dailyTrades,
  205. uptime: Math.round(process.uptime()),
  206. })
  207. }
  208. } catch (error: any) {
  209. this.logger.warn(`心跳检查失败: ${error.message}`)
  210. }
  211. }, 60000)
  212. // 内存监控 (每30秒)
  213. const memoryInterval = setInterval(() => {
  214. if (this.isShuttingDown) {
  215. clearInterval(memoryInterval)
  216. return
  217. }
  218. const usage = process.memoryUsage()
  219. const memoryMB = Math.round(usage.rss / 1024 / 1024)
  220. this.logger.performance('内存使用', memoryMB, {
  221. heap: Math.round(usage.heapUsed / 1024 / 1024),
  222. external: Math.round(usage.external / 1024 / 1024),
  223. })
  224. // 内存警告
  225. if (memoryMB > 500) {
  226. this.logger.warn(`⚠️ 内存使用过高: ${memoryMB}MB`)
  227. }
  228. // 内存泄漏检测
  229. if (memoryMB > 1000) {
  230. this.logger.critical(`🚨 内存可能泄漏: ${memoryMB}MB`)
  231. }
  232. }, 30000)
  233. }
  234. private setupSignalHandlers() {
  235. // 优雅关闭信号
  236. ;['SIGTERM', 'SIGINT'].forEach(signal => {
  237. process.on(signal, () => {
  238. console.log(`\n🛑 收到 ${signal} 信号,开始优雅关闭...`)
  239. this.gracefulShutdown()
  240. })
  241. })
  242. // 重载配置信号 (生产环境热更新)
  243. process.on('SIGUSR1', () => {
  244. this.logger.info('🔄 收到重载配置信号')
  245. this.reloadConfiguration()
  246. })
  247. // 错误处理
  248. process.on('uncaughtException', error => {
  249. this.logger.critical('💥 未捕获异常', error)
  250. console.error('💥 未捕获异常:', error)
  251. this.gracefulShutdown()
  252. })
  253. process.on('unhandledRejection', reason => {
  254. this.logger.critical('💥 未处理的Promise拒绝', undefined, { reason })
  255. console.error('💥 未处理的Promise拒绝:', reason)
  256. })
  257. }
  258. private async attemptSystemRestart() {
  259. this.logger.info('🔄 尝试系统自动恢复...')
  260. try {
  261. if (this.system) {
  262. await this.system.shutdown()
  263. this.system = undefined
  264. }
  265. // 等待5秒
  266. await new Promise(resolve => setTimeout(resolve, 5000))
  267. // 重新创建系统
  268. this.system = new CompleteTradingSystem()
  269. this.setupProductionEventHandlers()
  270. await this.system.start()
  271. this.logger.info('✅ 系统自动恢复成功')
  272. } catch (error: any) {
  273. this.logger.critical('❌ 系统自动恢复失败', error)
  274. process.exit(1)
  275. }
  276. }
  277. private async reloadConfiguration() {
  278. try {
  279. this.logger.info('🔧 开始重载配置...')
  280. // 这里可以实现配置热更新逻辑
  281. // 例如重新读取环境变量、配置文件等
  282. this.logger.info('✅ 配置重载完成')
  283. } catch (error: any) {
  284. this.logger.error('❌ 配置重载失败', error)
  285. }
  286. }
  287. private async gracefulShutdown() {
  288. if (this.isShuttingDown) return
  289. this.isShuttingDown = true
  290. const shutdownStart = Date.now()
  291. try {
  292. this.logger.info('🛑 开始优雅关闭系统...')
  293. // 1. 停止接受新请求
  294. if (this.healthCheckServer) {
  295. this.healthCheckServer.close()
  296. this.logger.info('✅ 健康检查服务器已关闭')
  297. }
  298. // 2. 关闭交易系统
  299. if (this.system) {
  300. await this.system.shutdown()
  301. this.logger.info('✅ 交易系统已关闭')
  302. }
  303. // 3. 等待现有操作完成 (最多30秒)
  304. const maxWait = 30000
  305. const remaining = maxWait - (Date.now() - shutdownStart)
  306. if (remaining > 0) {
  307. this.logger.info(`⏱️ 等待现有操作完成... (最多${remaining}ms)`)
  308. await new Promise(resolve => setTimeout(resolve, Math.min(remaining, 5000)))
  309. }
  310. const shutdownTime = Date.now() - shutdownStart
  311. this.logger.info(`✅ 系统优雅关闭完成 (用时${shutdownTime}ms)`)
  312. // 关闭日志系统
  313. this.logger.close()
  314. process.exit(0)
  315. } catch (error: any) {
  316. this.logger.critical('❌ 优雅关闭失败', error)
  317. console.error('❌ 优雅关闭失败:', error)
  318. process.exit(1)
  319. }
  320. }
  321. }
  322. // 启动生产系统
  323. if (import.meta.url === `file://${process.argv[1]}`) {
  324. // 设置默认环境变量
  325. process.env.NODE_ENV = process.env.NODE_ENV || 'production'
  326. const runner = new ProductionSystemRunner()
  327. runner.start().catch(error => {
  328. console.error('❌ 系统启动失败:', error)
  329. process.exit(1)
  330. })
  331. }
  332. export { ProductionSystemRunner }