amqplib-init 1.3.2 → 1.3.4

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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,13 @@
1
1
  # Changelog
2
2
 
3
+ ## [1.3.3] - 2026-01-24
4
+
5
+ ### 🐛 修复
6
+ - **修复 ES Module 支持**: 在 `package.json` 中添加 `"type": "module"`
7
+ - **修复 Rollup 配置**: 将 `rollup.config.js` 改名为 `rollup.config.cjs` 以支持 CommonJS
8
+
9
+ ---
10
+
3
11
  ## [1.3.2] - 2026-01-24
4
12
 
5
13
  ### 🐛 修复
@@ -1 +1 @@
1
- "use strict";var e=require("axios"),t=require("chalk-style"),s=require("amqplib"),n=require("happy-help");function i(e){return e&&e.__esModule&&Object.prototype.hasOwnProperty.call(e,"default")?e.default:e}const o=e,a=t;var c=class{constructor(){this.defaultConfig={channelName:"node-test-channel",prefetch:1,callback:()=>{},finish:()=>{},amqpLink:"",amqpAutoLink:"",heartbeat:60,timeout:3e5,delay:0,autoReload:0,queryHook:()=>{},initHook:()=>{},durable:!0,messageTimeout:9e5,reconnectDelay:5e3,maxReconnectAttempts:10}}resolveConfig(e={}){return{...this.defaultConfig,...e}}async resolveAmqpLink(e,t){if(!e)return t;try{a.log(`正在从 ${e} 获取连接信息...`);const s=await o.post(e),{info:n}=s.data;if(this._validateConnectionInfo(n)){const e=`amqp://${n.AMQPLIB_USER}:${n.AMQPLIB_PWD}@${n.AMQPLIB_PUB}:${n.AMQPLIB_PORT}`;return a.log(`✅ 自动获取连接信息成功: ${e}`),e}return a.error("❌ 获取的连接信息不完整,使用默认连接地址"),t}catch(e){return a.error("❌ 获取连接信息失败:",e.message),a.log("使用默认连接地址继续..."),t}}_validateConnectionInfo(e){return e&&e.AMQPLIB_USER&&e.AMQPLIB_PWD&&e.AMQPLIB_PUB&&e.AMQPLIB_PORT}};const r=s,h=t,l=n;var g=class{constructor(e){this.config=e,this.connection=null,this.channel=null,this.amqpLink="",this.reconnectInProgress=!1,this.reconnectAttempts=0,this.maxReconnectAttempts=e.maxReconnectAttempts||10}setAmqpLink(e){this.amqpLink=e}async initialize(){const{channelName:e,durable:t,prefetch:s,heartbeat:n,timeout:i,initHook:o,reconnectDelay:a}=this.config;try{return this.connection=await r.connect(this.amqpLink,{heartbeat:n,timeout:i}),this.channel=await this.connection.createChannel(),await this.channel.assertQueue(e,{durable:t}),await this.channel.prefetch(s),await o({channel:this.channel,connection:this.connection}),h.log(`已连接到RabbitMQ,频道: ${e}`),this._setupConnectionEvents(),this.channel}catch(e){throw h.error("初始化RabbitMQ连接时出错:",e),e}}async reconnect(){if(this.reconnectInProgress)return h.log("重连已在进行中,跳过此次重连请求"),this.channel;if(this.reconnectAttempts>=this.maxReconnectAttempts)return h.error(`❌ 已达到最大重连次数 ${this.maxReconnectAttempts},停止重连`),h.error("请检查 RabbitMQ 服务状态或网络连接"),null;this.reconnectInProgress=!0,this.reconnectAttempts++;try{h.error(`🔄 连接丢失,正在尝试第 ${this.reconnectAttempts}/${this.maxReconnectAttempts} 次重连...`),await this._cleanupOldChannel();const e=(this.config.reconnectDelay||5e3)/1e3;return await l.sleep(e),await this.initialize(),this.reconnectAttempts=0,h.log(`✅ 已重新连接到RabbitMQ,频道: ${this.config.channelName}`),this.channel}catch(e){if(h.error(`❌ 第 ${this.reconnectAttempts} 次重连失败:`,e.message),this.reconnectAttempts<this.maxReconnectAttempts){const e=this.config.reconnectDelay||5e3;setTimeout(()=>{this.reconnectInProgress=!1,this.reconnect()},e)}else h.error("❌ 已达到最大重连次数,停止重连");throw e}finally{this.reconnectInProgress=!1}}getChannel(){return this.channel}getConnection(){return this.connection}isConnected(){return this.connection&&this.channel&&!this.connection.connection.destroyed}async close(){try{this.channel&&(await this.channel.close(),this.channel=null),this.connection&&(await this.connection.close(),this.connection=null),h.log("RabbitMQ连接已关闭")}catch(e){h.error("关闭连接时出错:",e.message)}}_setupConnectionEvents(){this.connection.on("error",e=>{h.error("连接错误:",e.message),this.reconnect().catch(e=>{h.error("重连失败:",e.message)})}),this.connection.on("close",()=>{h.error("与RabbitMQ的连接已关闭"),this.reconnect().catch(e=>{h.error("重连失败:",e.message)})})}async _cleanupOldChannel(){if(this.channel){try{await this.channel.close()}catch(e){h.log("关闭旧channel时出错:",e.message)}this.channel=null}}getStats(){return{isConnected:this.isConnected(),reconnectAttempts:this.reconnectAttempts,maxReconnectAttempts:this.maxReconnectAttempts,reconnectInProgress:this.reconnectInProgress}}};const u=t,m=n;var p=class{constructor(e){this.config=e,this.processingMessages=new Set}async startConsuming(e){const{channelName:t,callback:s,delay:n}=this.config;return u.log(`开始消费: ${t}`),await e.consume(t,async t=>{null!==t?await this._handleMessage(t,e,s,n):u.log("收到null消息,队列可能为空或连接中断")},{noAck:!1}),()=>{this.processingMessages.clear(),u.log("已清理消息处理状态")}}async _handleMessage(e,t,s,n){const i=e.fields.deliveryTag;if(this.processingMessages.has(i))u.log(`消息 ${i} 已在处理中,跳过`);else{if(this.processingMessages.add(i),!this._isValidMessageContent(e))return u.log(`⚠️ 收到无效消息 ${i},内容为空或无法解析,自动确认以防止阻塞`),void this._acknowledgeMessage(e,t,i,0);try{const o=JSON.parse(e.content.toString());u.log(`🪴 队列收到消息: ${JSON.stringify(o)}`);const a=Date.now(),c=new Promise((e,t)=>{setTimeout(()=>{t(new Error(`消息处理超时 (${this.config.messageTimeout}ms)`))},this.config.messageTimeout)});try{await Promise.race([s(o),c]);const r=Date.now()-a;u.log(`☘️ 消息处理完成,延迟: ${n}ms,总时间: ${r}ms`),this._acknowledgeMessage(e,t,i,n)}catch(s){s.message.includes("超时")?u.error(`⏰ 消息 ${i} 处理超时 (${this.config.messageTimeout}ms)`):u.log("‼️ 处理消息返回错误:",s.message),await this._rejectMessage(e,t,i)}}catch(s){u.log("‼️ 处理消息时出错:",s.message),await this._rejectMessage(e,t,i)}}}_isValidMessageContent(e){try{if(!e||!e.content)return!1;const t=e.content.toString();return!(!t||""===t.trim())&&("null"!==t.toLowerCase()&&"undefined"!==t.toLowerCase()&&(JSON.parse(t),!0))}catch(e){return!1}}_acknowledgeMessage(e,t,s,n){this.processingMessages.has(s)&&setTimeout(()=>{try{t.ack(e),this.processingMessages.delete(s),u.log(`✅ 消息 ${s} 已确认`)}catch(e){u.error(`ACK消息 ${s} 时出错:`,e.message),this.processingMessages.delete(s)}},n)}async _rejectMessage(e,t,s){if(await m.sleep(5),this.processingMessages.has(s))try{t.reject(e,!0),this.processingMessages.delete(s),u.log(`❌ 消息 ${s} 已拒绝并重新排队`)}catch(e){u.error(`拒绝消息 ${s} 时出错:`,e.message),this.processingMessages.delete(s)}}clearProcessingMessages(){this.processingMessages.clear(),u.log("已清理所有消息处理状态")}getProcessingCount(){return this.processingMessages.size}};const d=t;const f=c,M=g,w=p,y=class{constructor(e){this.config=e,this.intervalId=null,this.isRunning=!1}start(e){const{autoReload:t,channelName:s,queryHook:n}=this.config;t<=0?d.log("自动重载功能未启用"):this.isRunning?d.log("自动重载监控已在运行中"):(this.isRunning=!0,d.log(`启动队列监控,间隔: ${t}ms`),this.intervalId=setInterval(async()=>{try{await this._checkQueueStatus(e,s,n)}catch(e){d.error("队列状态检查时出错:",e.message)}},t))}stop(){this.intervalId&&(clearInterval(this.intervalId),this.intervalId=null,this.isRunning=!1,d.log("自动重载监控已停止"))}restart(e){this.stop(),this.start(e)}isActive(){return this.isRunning}async _checkQueueStatus(e,t,s){try{const{messageCount:n}=await e.checkQueue(t),i=await s();d.log(`队列 ${t} 中有 ${n} 条消息,钩子状态: ${i?1:0}`)}catch(e){d.error("检查队列状态时出错:",e.message)}}getConfig(){return{autoReload:this.config.autoReload,isRunning:this.isRunning,intervalId:null!==this.intervalId}}},P=t;class AMQPInitializer{constructor(){this.configResolver=new f,this.connectionManager=null,this.messageProcessor=null,this.autoReloader=null,this.config=null}async init(e={}){try{this.config=this.configResolver.resolveConfig(e),P.log("配置解析完成");const t=await this.configResolver.resolveAmqpLink(this.config.amqpAutoLink,this.config.amqpLink);this.connectionManager=new M(this.config),this.messageProcessor=new w(this.config),this.autoReloader=new y(this.config),this.connectionManager.setAmqpLink(t);const s=await this.connectionManager.initialize();this._setupReconnectHandler(),await this.messageProcessor.startConsuming(s),P.log("消息处理器已启动"),this.autoReloader.start(s),this.config.finish(),P.log("AMQP初始化完成")}catch(e){throw P.error("AMQP初始化失败:",e.message),e}}_setupReconnectHandler(){const e=this.connectionManager.reconnect.bind(this.connectionManager);this.connectionManager.reconnect=async()=>{try{const t=await e();return this.messageProcessor.clearProcessingMessages(),await this.messageProcessor.startConsuming(t),P.log("重连后消息处理器已重新启动"),this.autoReloader.restart(t),P.log("重连后自动重载监控已重新启动"),t}catch(e){throw P.error("重连处理失败:",e.message),e}}}getStatus(){return{isConnected:!!this.connectionManager&&this.connectionManager.isConnected(),processingCount:this.messageProcessor?this.messageProcessor.getProcessingCount():0,autoReloaderActive:!!this.autoReloader&&this.autoReloader.isActive(),channelName:this.config?this.config.channelName:null}}async shutdown(){try{P.log("开始优雅关闭AMQP连接..."),this.autoReloader&&this.autoReloader.stop(),this.messageProcessor&&this.messageProcessor.clearProcessingMessages(),this.connectionManager&&await this.connectionManager.close(),P.log("AMQP连接已优雅关闭")}catch(e){P.error("关闭AMQP连接时出错:",e.message)}}}var R=i({async init(e){const t=new AMQPInitializer;return await t.init(e)},AMQPInitializer:AMQPInitializer});module.exports=R;
1
+ "use strict";var e=require("axios"),t=require("chalk-style"),s=require("amqplib"),n=require("happy-help");function i(e){return e&&e.__esModule&&Object.prototype.hasOwnProperty.call(e,"default")?e.default:e}const o=e,c=t;var a=class{constructor(){this.defaultConfig={channelName:"node-test-channel",prefetch:1,callback:()=>{},finish:()=>{},amqpLink:"",amqpAutoLink:"",heartbeat:60,timeout:3e5,delay:0,autoReload:0,queryHook:()=>{},initHook:()=>{},durable:!0,messageTimeout:9e5,reconnectDelay:5e3,maxReconnectAttempts:10}}resolveConfig(e={}){return{...this.defaultConfig,...e}}async resolveAmqpLink(e,t){if(!e)return t;try{c.log(`正在从 ${e} 获取连接信息...`);const s=await o.post(e),{info:n}=s.data;if(this._validateConnectionInfo(n)){const e=`amqp://${n.AMQPLIB_USER}:${n.AMQPLIB_PWD}@${n.AMQPLIB_PUB}:${n.AMQPLIB_PORT}`;return c.log(`✅ 自动获取连接信息成功: ${e}`),e}return c.error("❌ 获取的连接信息不完整,使用默认连接地址"),t}catch(e){return c.error("❌ 获取连接信息失败:",e.message),c.log("使用默认连接地址继续..."),t}}_validateConnectionInfo(e){return e&&e.AMQPLIB_USER&&e.AMQPLIB_PWD&&e.AMQPLIB_PUB&&e.AMQPLIB_PORT}};const r=s,h=t,l=n;var g=class{constructor(e){this.config=e,this.connection=null,this.channel=null,this.amqpLink="",this.reconnectInProgress=!1,this.reconnectAttempts=0,this.maxReconnectAttempts=e.maxReconnectAttempts||10}setAmqpLink(e){this.amqpLink=e}async initialize(){const{channelName:e,durable:t,prefetch:s,heartbeat:n,timeout:i,initHook:o,reconnectDelay:c}=this.config;try{return this.connection=await r.connect(this.amqpLink,{heartbeat:n,timeout:i}),this.channel=await this.connection.createChannel(),await this.channel.assertQueue(e,{durable:t}),await this.channel.prefetch(s),await o({channel:this.channel,connection:this.connection}),h.log(`已连接到RabbitMQ,频道: ${e}`),this._setupConnectionEvents(),this.channel}catch(e){throw h.error("初始化RabbitMQ连接时出错:",e),e}}async reconnect(){if(this.reconnectInProgress)return h.log("重连已在进行中,跳过此次重连请求"),this.channel;if(this.reconnectAttempts>=this.maxReconnectAttempts)return h.error(`❌ 已达到最大重连次数 ${this.maxReconnectAttempts},停止重连`),h.error("请检查 RabbitMQ 服务状态或网络连接"),null;this.reconnectInProgress=!0,this.reconnectAttempts++;try{h.error(`🔄 连接丢失,正在尝试第 ${this.reconnectAttempts}/${this.maxReconnectAttempts} 次重连...`),await this._cleanupOldChannel();const e=(this.config.reconnectDelay||5e3)/1e3;return await l.sleep(e),await this.initialize(),this.reconnectAttempts=0,h.log(`✅ 已重新连接到RabbitMQ,频道: ${this.config.channelName}`),this.channel}catch(e){if(h.error(`❌ 第 ${this.reconnectAttempts} 次重连失败:`,e.message),this.reconnectAttempts<this.maxReconnectAttempts){const e=this.config.reconnectDelay||5e3;setTimeout(()=>{this.reconnectInProgress=!1,this.reconnect()},e)}else h.error("❌ 已达到最大重连次数,停止重连");throw e}finally{this.reconnectInProgress=!1}}getChannel(){return this.channel}getConnection(){return this.connection}isConnected(){return this.connection&&this.channel&&!this.connection.connection.destroyed}async close(){try{this.channel&&(await this.channel.close(),this.channel=null),this.connection&&(await this.connection.close(),this.connection=null),h.log("RabbitMQ连接已关闭")}catch(e){h.error("关闭连接时出错:",e.message)}}_setupConnectionEvents(){this.connection.on("error",e=>{h.error("连接错误:",e.message),this.reconnect().catch(e=>{h.error("重连失败:",e.message)})}),this.connection.on("close",()=>{h.error("与RabbitMQ的连接已关闭"),this.reconnect().catch(e=>{h.error("重连失败:",e.message)})})}async _cleanupOldChannel(){if(this.channel){try{await this.channel.close()}catch(e){h.log("关闭旧channel时出错:",e.message)}this.channel=null}}getStats(){return{isConnected:this.isConnected(),reconnectAttempts:this.reconnectAttempts,maxReconnectAttempts:this.maxReconnectAttempts,reconnectInProgress:this.reconnectInProgress}}};const u=t,m=n;var p=class{constructor(e){this.config=e,this.processingMessages=new Set}async startConsuming(e){const{channelName:t,callback:s,delay:n}=this.config;return u.log(`开始消费: ${t}`),await e.consume(t,async t=>{null!==t?this._handleMessage(t,e,s,n).catch(e=>{u.error("处理消息时发生未捕获异常:",e)}):u.log("收到null消息,队列可能为空或连接中断")},{noAck:!1}),()=>{this.processingMessages.clear(),u.log("已清理消息处理状态")}}async _handleMessage(e,t,s,n){const i=e.fields.deliveryTag;if(this.processingMessages.has(i))u.log(`消息 ${i} 已在处理中,跳过`);else{if(this.processingMessages.add(i),!this._isValidMessageContent(e))return u.log(`⚠️ 收到无效消息 ${i},内容为空或无法解析,自动确认以防止阻塞`),void this._acknowledgeMessage(e,t,i,0);try{const o=JSON.parse(e.content.toString());u.log(`🪴 队列收到消息: ${JSON.stringify(o)}`);const c=Date.now(),a=new Promise((e,t)=>{setTimeout(()=>{t(new Error(`消息处理超时 (${this.config.messageTimeout}ms)`))},this.config.messageTimeout)});try{await Promise.race([s(o),a]);const r=Date.now()-c;u.log(`☘️ 消息处理完成,延迟: ${n}ms,总时间: ${r}ms`),this._acknowledgeMessage(e,t,i,n)}catch(s){s.message.includes("超时")?u.error(`⏰ 消息 ${i} 处理超时 (${this.config.messageTimeout}ms)`):u.log("‼️ 处理消息返回错误:",s.message),await this._rejectMessage(e,t,i)}}catch(s){u.log("‼️ 处理消息时出错:",s.message),await this._rejectMessage(e,t,i)}}}_isValidMessageContent(e){try{if(!e||!e.content)return!1;const t=e.content.toString();return!(!t||""===t.trim())&&("null"!==t.toLowerCase()&&"undefined"!==t.toLowerCase()&&(JSON.parse(t),!0))}catch(e){return!1}}_acknowledgeMessage(e,t,s,n){this.processingMessages.has(s)&&setTimeout(()=>{try{t.ack(e),this.processingMessages.delete(s),u.log(`✅ 消息 ${s} 已确认`)}catch(e){u.error(`ACK消息 ${s} 时出错:`,e.message),this.processingMessages.delete(s)}},n)}async _rejectMessage(e,t,s){if(await m.sleep(5),this.processingMessages.has(s))try{t.reject(e,!0),this.processingMessages.delete(s),u.log(`❌ 消息 ${s} 已拒绝并重新排队`)}catch(e){u.error(`拒绝消息 ${s} 时出错:`,e.message),this.processingMessages.delete(s)}}clearProcessingMessages(){this.processingMessages.clear(),u.log("已清理所有消息处理状态")}getProcessingCount(){return this.processingMessages.size}};const d=t;const f=a,M=g,w=p,y=class{constructor(e){this.config=e,this.intervalId=null,this.isRunning=!1}start(e){const{autoReload:t,channelName:s,queryHook:n}=this.config;t<=0?d.log("自动重载功能未启用"):this.isRunning?d.log("自动重载监控已在运行中"):(this.isRunning=!0,d.log(`启动队列监控,间隔: ${t}ms`),this.intervalId=setInterval(async()=>{try{await this._checkQueueStatus(e,s,n)}catch(e){d.error("队列状态检查时出错:",e.message)}},t))}stop(){this.intervalId&&(clearInterval(this.intervalId),this.intervalId=null,this.isRunning=!1,d.log("自动重载监控已停止"))}restart(e){this.stop(),this.start(e)}isActive(){return this.isRunning}async _checkQueueStatus(e,t,s){try{const{messageCount:n}=await e.checkQueue(t),i=await s();d.log(`队列 ${t} 中有 ${n} 条消息,钩子状态: ${i?1:0}`)}catch(e){d.error("检查队列状态时出错:",e.message)}}getConfig(){return{autoReload:this.config.autoReload,isRunning:this.isRunning,intervalId:null!==this.intervalId}}},P=t;class AMQPInitializer{constructor(){this.configResolver=new f,this.connectionManager=null,this.messageProcessor=null,this.autoReloader=null,this.config=null}async init(e={}){try{this.config=this.configResolver.resolveConfig(e),P.log("配置解析完成");const t=await this.configResolver.resolveAmqpLink(this.config.amqpAutoLink,this.config.amqpLink);this.connectionManager=new M(this.config),this.messageProcessor=new w(this.config),this.autoReloader=new y(this.config),this.connectionManager.setAmqpLink(t);const s=await this.connectionManager.initialize();this._setupReconnectHandler(),await this.messageProcessor.startConsuming(s),P.log("消息处理器已启动"),this.autoReloader.start(s),this.config.finish(),P.log("AMQP初始化完成")}catch(e){throw P.error("AMQP初始化失败:",e.message),e}}_setupReconnectHandler(){const e=this.connectionManager.reconnect.bind(this.connectionManager);this.connectionManager.reconnect=async()=>{try{const t=await e();return this.messageProcessor.clearProcessingMessages(),await this.messageProcessor.startConsuming(t),P.log("重连后消息处理器已重新启动"),this.autoReloader.restart(t),P.log("重连后自动重载监控已重新启动"),t}catch(e){throw P.error("重连处理失败:",e.message),e}}}getStatus(){return{isConnected:!!this.connectionManager&&this.connectionManager.isConnected(),processingCount:this.messageProcessor?this.messageProcessor.getProcessingCount():0,autoReloaderActive:!!this.autoReloader&&this.autoReloader.isActive(),channelName:this.config?this.config.channelName:null}}async shutdown(){try{P.log("开始优雅关闭AMQP连接..."),this.autoReloader&&this.autoReloader.stop(),this.messageProcessor&&this.messageProcessor.clearProcessingMessages(),this.connectionManager&&await this.connectionManager.close(),P.log("AMQP连接已优雅关闭")}catch(e){P.error("关闭AMQP连接时出错:",e.message)}}}var R=i({async init(e){const t=new AMQPInitializer;return await t.init(e)},AMQPInitializer:AMQPInitializer});module.exports=R;
@@ -1 +1 @@
1
- import e from"axios";import t from"chalk-style";import s from"amqplib";import n from"happy-help";function i(e){return e&&e.__esModule&&Object.prototype.hasOwnProperty.call(e,"default")?e.default:e}const o=e,a=t;var c=class{constructor(){this.defaultConfig={channelName:"node-test-channel",prefetch:1,callback:()=>{},finish:()=>{},amqpLink:"",amqpAutoLink:"",heartbeat:60,timeout:3e5,delay:0,autoReload:0,queryHook:()=>{},initHook:()=>{},durable:!0,messageTimeout:9e5,reconnectDelay:5e3,maxReconnectAttempts:10}}resolveConfig(e={}){return{...this.defaultConfig,...e}}async resolveAmqpLink(e,t){if(!e)return t;try{a.log(`正在从 ${e} 获取连接信息...`);const s=await o.post(e),{info:n}=s.data;if(this._validateConnectionInfo(n)){const e=`amqp://${n.AMQPLIB_USER}:${n.AMQPLIB_PWD}@${n.AMQPLIB_PUB}:${n.AMQPLIB_PORT}`;return a.log(`✅ 自动获取连接信息成功: ${e}`),e}return a.error("❌ 获取的连接信息不完整,使用默认连接地址"),t}catch(e){return a.error("❌ 获取连接信息失败:",e.message),a.log("使用默认连接地址继续..."),t}}_validateConnectionInfo(e){return e&&e.AMQPLIB_USER&&e.AMQPLIB_PWD&&e.AMQPLIB_PUB&&e.AMQPLIB_PORT}};const r=s,h=t,l=n;var g=class{constructor(e){this.config=e,this.connection=null,this.channel=null,this.amqpLink="",this.reconnectInProgress=!1,this.reconnectAttempts=0,this.maxReconnectAttempts=e.maxReconnectAttempts||10}setAmqpLink(e){this.amqpLink=e}async initialize(){const{channelName:e,durable:t,prefetch:s,heartbeat:n,timeout:i,initHook:o,reconnectDelay:a}=this.config;try{return this.connection=await r.connect(this.amqpLink,{heartbeat:n,timeout:i}),this.channel=await this.connection.createChannel(),await this.channel.assertQueue(e,{durable:t}),await this.channel.prefetch(s),await o({channel:this.channel,connection:this.connection}),h.log(`已连接到RabbitMQ,频道: ${e}`),this._setupConnectionEvents(),this.channel}catch(e){throw h.error("初始化RabbitMQ连接时出错:",e),e}}async reconnect(){if(this.reconnectInProgress)return h.log("重连已在进行中,跳过此次重连请求"),this.channel;if(this.reconnectAttempts>=this.maxReconnectAttempts)return h.error(`❌ 已达到最大重连次数 ${this.maxReconnectAttempts},停止重连`),h.error("请检查 RabbitMQ 服务状态或网络连接"),null;this.reconnectInProgress=!0,this.reconnectAttempts++;try{h.error(`🔄 连接丢失,正在尝试第 ${this.reconnectAttempts}/${this.maxReconnectAttempts} 次重连...`),await this._cleanupOldChannel();const e=(this.config.reconnectDelay||5e3)/1e3;return await l.sleep(e),await this.initialize(),this.reconnectAttempts=0,h.log(`✅ 已重新连接到RabbitMQ,频道: ${this.config.channelName}`),this.channel}catch(e){if(h.error(`❌ 第 ${this.reconnectAttempts} 次重连失败:`,e.message),this.reconnectAttempts<this.maxReconnectAttempts){const e=this.config.reconnectDelay||5e3;setTimeout(()=>{this.reconnectInProgress=!1,this.reconnect()},e)}else h.error("❌ 已达到最大重连次数,停止重连");throw e}finally{this.reconnectInProgress=!1}}getChannel(){return this.channel}getConnection(){return this.connection}isConnected(){return this.connection&&this.channel&&!this.connection.connection.destroyed}async close(){try{this.channel&&(await this.channel.close(),this.channel=null),this.connection&&(await this.connection.close(),this.connection=null),h.log("RabbitMQ连接已关闭")}catch(e){h.error("关闭连接时出错:",e.message)}}_setupConnectionEvents(){this.connection.on("error",e=>{h.error("连接错误:",e.message),this.reconnect().catch(e=>{h.error("重连失败:",e.message)})}),this.connection.on("close",()=>{h.error("与RabbitMQ的连接已关闭"),this.reconnect().catch(e=>{h.error("重连失败:",e.message)})})}async _cleanupOldChannel(){if(this.channel){try{await this.channel.close()}catch(e){h.log("关闭旧channel时出错:",e.message)}this.channel=null}}getStats(){return{isConnected:this.isConnected(),reconnectAttempts:this.reconnectAttempts,maxReconnectAttempts:this.maxReconnectAttempts,reconnectInProgress:this.reconnectInProgress}}};const u=t,m=n;var p=class{constructor(e){this.config=e,this.processingMessages=new Set}async startConsuming(e){const{channelName:t,callback:s,delay:n}=this.config;return u.log(`开始消费: ${t}`),await e.consume(t,async t=>{null!==t?await this._handleMessage(t,e,s,n):u.log("收到null消息,队列可能为空或连接中断")},{noAck:!1}),()=>{this.processingMessages.clear(),u.log("已清理消息处理状态")}}async _handleMessage(e,t,s,n){const i=e.fields.deliveryTag;if(this.processingMessages.has(i))u.log(`消息 ${i} 已在处理中,跳过`);else{if(this.processingMessages.add(i),!this._isValidMessageContent(e))return u.log(`⚠️ 收到无效消息 ${i},内容为空或无法解析,自动确认以防止阻塞`),void this._acknowledgeMessage(e,t,i,0);try{const o=JSON.parse(e.content.toString());u.log(`🪴 队列收到消息: ${JSON.stringify(o)}`);const a=Date.now(),c=new Promise((e,t)=>{setTimeout(()=>{t(new Error(`消息处理超时 (${this.config.messageTimeout}ms)`))},this.config.messageTimeout)});try{await Promise.race([s(o),c]);const r=Date.now()-a;u.log(`☘️ 消息处理完成,延迟: ${n}ms,总时间: ${r}ms`),this._acknowledgeMessage(e,t,i,n)}catch(s){s.message.includes("超时")?u.error(`⏰ 消息 ${i} 处理超时 (${this.config.messageTimeout}ms)`):u.log("‼️ 处理消息返回错误:",s.message),await this._rejectMessage(e,t,i)}}catch(s){u.log("‼️ 处理消息时出错:",s.message),await this._rejectMessage(e,t,i)}}}_isValidMessageContent(e){try{if(!e||!e.content)return!1;const t=e.content.toString();return!(!t||""===t.trim())&&("null"!==t.toLowerCase()&&"undefined"!==t.toLowerCase()&&(JSON.parse(t),!0))}catch(e){return!1}}_acknowledgeMessage(e,t,s,n){this.processingMessages.has(s)&&setTimeout(()=>{try{t.ack(e),this.processingMessages.delete(s),u.log(`✅ 消息 ${s} 已确认`)}catch(e){u.error(`ACK消息 ${s} 时出错:`,e.message),this.processingMessages.delete(s)}},n)}async _rejectMessage(e,t,s){if(await m.sleep(5),this.processingMessages.has(s))try{t.reject(e,!0),this.processingMessages.delete(s),u.log(`❌ 消息 ${s} 已拒绝并重新排队`)}catch(e){u.error(`拒绝消息 ${s} 时出错:`,e.message),this.processingMessages.delete(s)}}clearProcessingMessages(){this.processingMessages.clear(),u.log("已清理所有消息处理状态")}getProcessingCount(){return this.processingMessages.size}};const d=t;const f=c,M=g,w=p,y=class{constructor(e){this.config=e,this.intervalId=null,this.isRunning=!1}start(e){const{autoReload:t,channelName:s,queryHook:n}=this.config;t<=0?d.log("自动重载功能未启用"):this.isRunning?d.log("自动重载监控已在运行中"):(this.isRunning=!0,d.log(`启动队列监控,间隔: ${t}ms`),this.intervalId=setInterval(async()=>{try{await this._checkQueueStatus(e,s,n)}catch(e){d.error("队列状态检查时出错:",e.message)}},t))}stop(){this.intervalId&&(clearInterval(this.intervalId),this.intervalId=null,this.isRunning=!1,d.log("自动重载监控已停止"))}restart(e){this.stop(),this.start(e)}isActive(){return this.isRunning}async _checkQueueStatus(e,t,s){try{const{messageCount:n}=await e.checkQueue(t),i=await s();d.log(`队列 ${t} 中有 ${n} 条消息,钩子状态: ${i?1:0}`)}catch(e){d.error("检查队列状态时出错:",e.message)}}getConfig(){return{autoReload:this.config.autoReload,isRunning:this.isRunning,intervalId:null!==this.intervalId}}},P=t;class AMQPInitializer{constructor(){this.configResolver=new f,this.connectionManager=null,this.messageProcessor=null,this.autoReloader=null,this.config=null}async init(e={}){try{this.config=this.configResolver.resolveConfig(e),P.log("配置解析完成");const t=await this.configResolver.resolveAmqpLink(this.config.amqpAutoLink,this.config.amqpLink);this.connectionManager=new M(this.config),this.messageProcessor=new w(this.config),this.autoReloader=new y(this.config),this.connectionManager.setAmqpLink(t);const s=await this.connectionManager.initialize();this._setupReconnectHandler(),await this.messageProcessor.startConsuming(s),P.log("消息处理器已启动"),this.autoReloader.start(s),this.config.finish(),P.log("AMQP初始化完成")}catch(e){throw P.error("AMQP初始化失败:",e.message),e}}_setupReconnectHandler(){const e=this.connectionManager.reconnect.bind(this.connectionManager);this.connectionManager.reconnect=async()=>{try{const t=await e();return this.messageProcessor.clearProcessingMessages(),await this.messageProcessor.startConsuming(t),P.log("重连后消息处理器已重新启动"),this.autoReloader.restart(t),P.log("重连后自动重载监控已重新启动"),t}catch(e){throw P.error("重连处理失败:",e.message),e}}}getStatus(){return{isConnected:!!this.connectionManager&&this.connectionManager.isConnected(),processingCount:this.messageProcessor?this.messageProcessor.getProcessingCount():0,autoReloaderActive:!!this.autoReloader&&this.autoReloader.isActive(),channelName:this.config?this.config.channelName:null}}async shutdown(){try{P.log("开始优雅关闭AMQP连接..."),this.autoReloader&&this.autoReloader.stop(),this.messageProcessor&&this.messageProcessor.clearProcessingMessages(),this.connectionManager&&await this.connectionManager.close(),P.log("AMQP连接已优雅关闭")}catch(e){P.error("关闭AMQP连接时出错:",e.message)}}}var R=i({async init(e){const t=new AMQPInitializer;return await t.init(e)},AMQPInitializer:AMQPInitializer});export{R as default};
1
+ import e from"axios";import t from"chalk-style";import s from"amqplib";import n from"happy-help";function i(e){return e&&e.__esModule&&Object.prototype.hasOwnProperty.call(e,"default")?e.default:e}const o=e,a=t;var c=class{constructor(){this.defaultConfig={channelName:"node-test-channel",prefetch:1,callback:()=>{},finish:()=>{},amqpLink:"",amqpAutoLink:"",heartbeat:60,timeout:3e5,delay:0,autoReload:0,queryHook:()=>{},initHook:()=>{},durable:!0,messageTimeout:9e5,reconnectDelay:5e3,maxReconnectAttempts:10}}resolveConfig(e={}){return{...this.defaultConfig,...e}}async resolveAmqpLink(e,t){if(!e)return t;try{a.log(`正在从 ${e} 获取连接信息...`);const s=await o.post(e),{info:n}=s.data;if(this._validateConnectionInfo(n)){const e=`amqp://${n.AMQPLIB_USER}:${n.AMQPLIB_PWD}@${n.AMQPLIB_PUB}:${n.AMQPLIB_PORT}`;return a.log(`✅ 自动获取连接信息成功: ${e}`),e}return a.error("❌ 获取的连接信息不完整,使用默认连接地址"),t}catch(e){return a.error("❌ 获取连接信息失败:",e.message),a.log("使用默认连接地址继续..."),t}}_validateConnectionInfo(e){return e&&e.AMQPLIB_USER&&e.AMQPLIB_PWD&&e.AMQPLIB_PUB&&e.AMQPLIB_PORT}};const r=s,h=t,l=n;var g=class{constructor(e){this.config=e,this.connection=null,this.channel=null,this.amqpLink="",this.reconnectInProgress=!1,this.reconnectAttempts=0,this.maxReconnectAttempts=e.maxReconnectAttempts||10}setAmqpLink(e){this.amqpLink=e}async initialize(){const{channelName:e,durable:t,prefetch:s,heartbeat:n,timeout:i,initHook:o,reconnectDelay:a}=this.config;try{return this.connection=await r.connect(this.amqpLink,{heartbeat:n,timeout:i}),this.channel=await this.connection.createChannel(),await this.channel.assertQueue(e,{durable:t}),await this.channel.prefetch(s),await o({channel:this.channel,connection:this.connection}),h.log(`已连接到RabbitMQ,频道: ${e}`),this._setupConnectionEvents(),this.channel}catch(e){throw h.error("初始化RabbitMQ连接时出错:",e),e}}async reconnect(){if(this.reconnectInProgress)return h.log("重连已在进行中,跳过此次重连请求"),this.channel;if(this.reconnectAttempts>=this.maxReconnectAttempts)return h.error(`❌ 已达到最大重连次数 ${this.maxReconnectAttempts},停止重连`),h.error("请检查 RabbitMQ 服务状态或网络连接"),null;this.reconnectInProgress=!0,this.reconnectAttempts++;try{h.error(`🔄 连接丢失,正在尝试第 ${this.reconnectAttempts}/${this.maxReconnectAttempts} 次重连...`),await this._cleanupOldChannel();const e=(this.config.reconnectDelay||5e3)/1e3;return await l.sleep(e),await this.initialize(),this.reconnectAttempts=0,h.log(`✅ 已重新连接到RabbitMQ,频道: ${this.config.channelName}`),this.channel}catch(e){if(h.error(`❌ 第 ${this.reconnectAttempts} 次重连失败:`,e.message),this.reconnectAttempts<this.maxReconnectAttempts){const e=this.config.reconnectDelay||5e3;setTimeout(()=>{this.reconnectInProgress=!1,this.reconnect()},e)}else h.error("❌ 已达到最大重连次数,停止重连");throw e}finally{this.reconnectInProgress=!1}}getChannel(){return this.channel}getConnection(){return this.connection}isConnected(){return this.connection&&this.channel&&!this.connection.connection.destroyed}async close(){try{this.channel&&(await this.channel.close(),this.channel=null),this.connection&&(await this.connection.close(),this.connection=null),h.log("RabbitMQ连接已关闭")}catch(e){h.error("关闭连接时出错:",e.message)}}_setupConnectionEvents(){this.connection.on("error",e=>{h.error("连接错误:",e.message),this.reconnect().catch(e=>{h.error("重连失败:",e.message)})}),this.connection.on("close",()=>{h.error("与RabbitMQ的连接已关闭"),this.reconnect().catch(e=>{h.error("重连失败:",e.message)})})}async _cleanupOldChannel(){if(this.channel){try{await this.channel.close()}catch(e){h.log("关闭旧channel时出错:",e.message)}this.channel=null}}getStats(){return{isConnected:this.isConnected(),reconnectAttempts:this.reconnectAttempts,maxReconnectAttempts:this.maxReconnectAttempts,reconnectInProgress:this.reconnectInProgress}}};const u=t,m=n;var p=class{constructor(e){this.config=e,this.processingMessages=new Set}async startConsuming(e){const{channelName:t,callback:s,delay:n}=this.config;return u.log(`开始消费: ${t}`),await e.consume(t,async t=>{null!==t?this._handleMessage(t,e,s,n).catch(e=>{u.error("处理消息时发生未捕获异常:",e)}):u.log("收到null消息,队列可能为空或连接中断")},{noAck:!1}),()=>{this.processingMessages.clear(),u.log("已清理消息处理状态")}}async _handleMessage(e,t,s,n){const i=e.fields.deliveryTag;if(this.processingMessages.has(i))u.log(`消息 ${i} 已在处理中,跳过`);else{if(this.processingMessages.add(i),!this._isValidMessageContent(e))return u.log(`⚠️ 收到无效消息 ${i},内容为空或无法解析,自动确认以防止阻塞`),void this._acknowledgeMessage(e,t,i,0);try{const o=JSON.parse(e.content.toString());u.log(`🪴 队列收到消息: ${JSON.stringify(o)}`);const a=Date.now(),c=new Promise((e,t)=>{setTimeout(()=>{t(new Error(`消息处理超时 (${this.config.messageTimeout}ms)`))},this.config.messageTimeout)});try{await Promise.race([s(o),c]);const r=Date.now()-a;u.log(`☘️ 消息处理完成,延迟: ${n}ms,总时间: ${r}ms`),this._acknowledgeMessage(e,t,i,n)}catch(s){s.message.includes("超时")?u.error(`⏰ 消息 ${i} 处理超时 (${this.config.messageTimeout}ms)`):u.log("‼️ 处理消息返回错误:",s.message),await this._rejectMessage(e,t,i)}}catch(s){u.log("‼️ 处理消息时出错:",s.message),await this._rejectMessage(e,t,i)}}}_isValidMessageContent(e){try{if(!e||!e.content)return!1;const t=e.content.toString();return!(!t||""===t.trim())&&("null"!==t.toLowerCase()&&"undefined"!==t.toLowerCase()&&(JSON.parse(t),!0))}catch(e){return!1}}_acknowledgeMessage(e,t,s,n){this.processingMessages.has(s)&&setTimeout(()=>{try{t.ack(e),this.processingMessages.delete(s),u.log(`✅ 消息 ${s} 已确认`)}catch(e){u.error(`ACK消息 ${s} 时出错:`,e.message),this.processingMessages.delete(s)}},n)}async _rejectMessage(e,t,s){if(await m.sleep(5),this.processingMessages.has(s))try{t.reject(e,!0),this.processingMessages.delete(s),u.log(`❌ 消息 ${s} 已拒绝并重新排队`)}catch(e){u.error(`拒绝消息 ${s} 时出错:`,e.message),this.processingMessages.delete(s)}}clearProcessingMessages(){this.processingMessages.clear(),u.log("已清理所有消息处理状态")}getProcessingCount(){return this.processingMessages.size}};const d=t;const f=c,M=g,w=p,y=class{constructor(e){this.config=e,this.intervalId=null,this.isRunning=!1}start(e){const{autoReload:t,channelName:s,queryHook:n}=this.config;t<=0?d.log("自动重载功能未启用"):this.isRunning?d.log("自动重载监控已在运行中"):(this.isRunning=!0,d.log(`启动队列监控,间隔: ${t}ms`),this.intervalId=setInterval(async()=>{try{await this._checkQueueStatus(e,s,n)}catch(e){d.error("队列状态检查时出错:",e.message)}},t))}stop(){this.intervalId&&(clearInterval(this.intervalId),this.intervalId=null,this.isRunning=!1,d.log("自动重载监控已停止"))}restart(e){this.stop(),this.start(e)}isActive(){return this.isRunning}async _checkQueueStatus(e,t,s){try{const{messageCount:n}=await e.checkQueue(t),i=await s();d.log(`队列 ${t} 中有 ${n} 条消息,钩子状态: ${i?1:0}`)}catch(e){d.error("检查队列状态时出错:",e.message)}}getConfig(){return{autoReload:this.config.autoReload,isRunning:this.isRunning,intervalId:null!==this.intervalId}}},P=t;class AMQPInitializer{constructor(){this.configResolver=new f,this.connectionManager=null,this.messageProcessor=null,this.autoReloader=null,this.config=null}async init(e={}){try{this.config=this.configResolver.resolveConfig(e),P.log("配置解析完成");const t=await this.configResolver.resolveAmqpLink(this.config.amqpAutoLink,this.config.amqpLink);this.connectionManager=new M(this.config),this.messageProcessor=new w(this.config),this.autoReloader=new y(this.config),this.connectionManager.setAmqpLink(t);const s=await this.connectionManager.initialize();this._setupReconnectHandler(),await this.messageProcessor.startConsuming(s),P.log("消息处理器已启动"),this.autoReloader.start(s),this.config.finish(),P.log("AMQP初始化完成")}catch(e){throw P.error("AMQP初始化失败:",e.message),e}}_setupReconnectHandler(){const e=this.connectionManager.reconnect.bind(this.connectionManager);this.connectionManager.reconnect=async()=>{try{const t=await e();return this.messageProcessor.clearProcessingMessages(),await this.messageProcessor.startConsuming(t),P.log("重连后消息处理器已重新启动"),this.autoReloader.restart(t),P.log("重连后自动重载监控已重新启动"),t}catch(e){throw P.error("重连处理失败:",e.message),e}}}getStatus(){return{isConnected:!!this.connectionManager&&this.connectionManager.isConnected(),processingCount:this.messageProcessor?this.messageProcessor.getProcessingCount():0,autoReloaderActive:!!this.autoReloader&&this.autoReloader.isActive(),channelName:this.config?this.config.channelName:null}}async shutdown(){try{P.log("开始优雅关闭AMQP连接..."),this.autoReloader&&this.autoReloader.stop(),this.messageProcessor&&this.messageProcessor.clearProcessingMessages(),this.connectionManager&&await this.connectionManager.close(),P.log("AMQP连接已优雅关闭")}catch(e){P.error("关闭AMQP连接时出错:",e.message)}}}var R=i({async init(e){const t=new AMQPInitializer;return await t.init(e)},AMQPInitializer:AMQPInitializer});export{R as default};
@@ -1 +1 @@
1
- !function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t(require("axios"),require("chalk-style"),require("amqplib"),require("happy-help")):"function"==typeof define&&define.amd?define(["axios","chalk-style","amqplib","happy-help"],t):(e="undefined"!=typeof globalThis?globalThis:e||self).AmqplibInit=t(e.require$$0,e.require$$1,e.require$$0$1,e.require$$2)}(this,function(e,t,s,n){"use strict";function i(e){return e&&e.__esModule&&Object.prototype.hasOwnProperty.call(e,"default")?e.default:e}const o=e,a=t;var c=class{constructor(){this.defaultConfig={channelName:"node-test-channel",prefetch:1,callback:()=>{},finish:()=>{},amqpLink:"",amqpAutoLink:"",heartbeat:60,timeout:3e5,delay:0,autoReload:0,queryHook:()=>{},initHook:()=>{},durable:!0,messageTimeout:9e5,reconnectDelay:5e3,maxReconnectAttempts:10}}resolveConfig(e={}){return{...this.defaultConfig,...e}}async resolveAmqpLink(e,t){if(!e)return t;try{a.log(`正在从 ${e} 获取连接信息...`);const s=await o.post(e),{info:n}=s.data;if(this._validateConnectionInfo(n)){const e=`amqp://${n.AMQPLIB_USER}:${n.AMQPLIB_PWD}@${n.AMQPLIB_PUB}:${n.AMQPLIB_PORT}`;return a.log(`✅ 自动获取连接信息成功: ${e}`),e}return a.error("❌ 获取的连接信息不完整,使用默认连接地址"),t}catch(e){return a.error("❌ 获取连接信息失败:",e.message),a.log("使用默认连接地址继续..."),t}}_validateConnectionInfo(e){return e&&e.AMQPLIB_USER&&e.AMQPLIB_PWD&&e.AMQPLIB_PUB&&e.AMQPLIB_PORT}};const r=s,h=t,l=n;var g=class{constructor(e){this.config=e,this.connection=null,this.channel=null,this.amqpLink="",this.reconnectInProgress=!1,this.reconnectAttempts=0,this.maxReconnectAttempts=e.maxReconnectAttempts||10}setAmqpLink(e){this.amqpLink=e}async initialize(){const{channelName:e,durable:t,prefetch:s,heartbeat:n,timeout:i,initHook:o,reconnectDelay:a}=this.config;try{return this.connection=await r.connect(this.amqpLink,{heartbeat:n,timeout:i}),this.channel=await this.connection.createChannel(),await this.channel.assertQueue(e,{durable:t}),await this.channel.prefetch(s),await o({channel:this.channel,connection:this.connection}),h.log(`已连接到RabbitMQ,频道: ${e}`),this._setupConnectionEvents(),this.channel}catch(e){throw h.error("初始化RabbitMQ连接时出错:",e),e}}async reconnect(){if(this.reconnectInProgress)return h.log("重连已在进行中,跳过此次重连请求"),this.channel;if(this.reconnectAttempts>=this.maxReconnectAttempts)return h.error(`❌ 已达到最大重连次数 ${this.maxReconnectAttempts},停止重连`),h.error("请检查 RabbitMQ 服务状态或网络连接"),null;this.reconnectInProgress=!0,this.reconnectAttempts++;try{h.error(`🔄 连接丢失,正在尝试第 ${this.reconnectAttempts}/${this.maxReconnectAttempts} 次重连...`),await this._cleanupOldChannel();const e=(this.config.reconnectDelay||5e3)/1e3;return await l.sleep(e),await this.initialize(),this.reconnectAttempts=0,h.log(`✅ 已重新连接到RabbitMQ,频道: ${this.config.channelName}`),this.channel}catch(e){if(h.error(`❌ 第 ${this.reconnectAttempts} 次重连失败:`,e.message),this.reconnectAttempts<this.maxReconnectAttempts){const e=this.config.reconnectDelay||5e3;setTimeout(()=>{this.reconnectInProgress=!1,this.reconnect()},e)}else h.error("❌ 已达到最大重连次数,停止重连");throw e}finally{this.reconnectInProgress=!1}}getChannel(){return this.channel}getConnection(){return this.connection}isConnected(){return this.connection&&this.channel&&!this.connection.connection.destroyed}async close(){try{this.channel&&(await this.channel.close(),this.channel=null),this.connection&&(await this.connection.close(),this.connection=null),h.log("RabbitMQ连接已关闭")}catch(e){h.error("关闭连接时出错:",e.message)}}_setupConnectionEvents(){this.connection.on("error",e=>{h.error("连接错误:",e.message),this.reconnect().catch(e=>{h.error("重连失败:",e.message)})}),this.connection.on("close",()=>{h.error("与RabbitMQ的连接已关闭"),this.reconnect().catch(e=>{h.error("重连失败:",e.message)})})}async _cleanupOldChannel(){if(this.channel){try{await this.channel.close()}catch(e){h.log("关闭旧channel时出错:",e.message)}this.channel=null}}getStats(){return{isConnected:this.isConnected(),reconnectAttempts:this.reconnectAttempts,maxReconnectAttempts:this.maxReconnectAttempts,reconnectInProgress:this.reconnectInProgress}}};const u=t,m=n;var p=class{constructor(e){this.config=e,this.processingMessages=new Set}async startConsuming(e){const{channelName:t,callback:s,delay:n}=this.config;return u.log(`开始消费: ${t}`),await e.consume(t,async t=>{null!==t?await this._handleMessage(t,e,s,n):u.log("收到null消息,队列可能为空或连接中断")},{noAck:!1}),()=>{this.processingMessages.clear(),u.log("已清理消息处理状态")}}async _handleMessage(e,t,s,n){const i=e.fields.deliveryTag;if(this.processingMessages.has(i))u.log(`消息 ${i} 已在处理中,跳过`);else{if(this.processingMessages.add(i),!this._isValidMessageContent(e))return u.log(`⚠️ 收到无效消息 ${i},内容为空或无法解析,自动确认以防止阻塞`),void this._acknowledgeMessage(e,t,i,0);try{const o=JSON.parse(e.content.toString());u.log(`🪴 队列收到消息: ${JSON.stringify(o)}`);const a=Date.now(),c=new Promise((e,t)=>{setTimeout(()=>{t(new Error(`消息处理超时 (${this.config.messageTimeout}ms)`))},this.config.messageTimeout)});try{await Promise.race([s(o),c]);const r=Date.now()-a;u.log(`☘️ 消息处理完成,延迟: ${n}ms,总时间: ${r}ms`),this._acknowledgeMessage(e,t,i,n)}catch(s){s.message.includes("超时")?u.error(`⏰ 消息 ${i} 处理超时 (${this.config.messageTimeout}ms)`):u.log("‼️ 处理消息返回错误:",s.message),await this._rejectMessage(e,t,i)}}catch(s){u.log("‼️ 处理消息时出错:",s.message),await this._rejectMessage(e,t,i)}}}_isValidMessageContent(e){try{if(!e||!e.content)return!1;const t=e.content.toString();return!(!t||""===t.trim())&&("null"!==t.toLowerCase()&&"undefined"!==t.toLowerCase()&&(JSON.parse(t),!0))}catch(e){return!1}}_acknowledgeMessage(e,t,s,n){this.processingMessages.has(s)&&setTimeout(()=>{try{t.ack(e),this.processingMessages.delete(s),u.log(`✅ 消息 ${s} 已确认`)}catch(e){u.error(`ACK消息 ${s} 时出错:`,e.message),this.processingMessages.delete(s)}},n)}async _rejectMessage(e,t,s){if(await m.sleep(5),this.processingMessages.has(s))try{t.reject(e,!0),this.processingMessages.delete(s),u.log(`❌ 消息 ${s} 已拒绝并重新排队`)}catch(e){u.error(`拒绝消息 ${s} 时出错:`,e.message),this.processingMessages.delete(s)}}clearProcessingMessages(){this.processingMessages.clear(),u.log("已清理所有消息处理状态")}getProcessingCount(){return this.processingMessages.size}};const d=t;const f=c,M=g,y=p,w=class{constructor(e){this.config=e,this.intervalId=null,this.isRunning=!1}start(e){const{autoReload:t,channelName:s,queryHook:n}=this.config;t<=0?d.log("自动重载功能未启用"):this.isRunning?d.log("自动重载监控已在运行中"):(this.isRunning=!0,d.log(`启动队列监控,间隔: ${t}ms`),this.intervalId=setInterval(async()=>{try{await this._checkQueueStatus(e,s,n)}catch(e){d.error("队列状态检查时出错:",e.message)}},t))}stop(){this.intervalId&&(clearInterval(this.intervalId),this.intervalId=null,this.isRunning=!1,d.log("自动重载监控已停止"))}restart(e){this.stop(),this.start(e)}isActive(){return this.isRunning}async _checkQueueStatus(e,t,s){try{const{messageCount:n}=await e.checkQueue(t),i=await s();d.log(`队列 ${t} 中有 ${n} 条消息,钩子状态: ${i?1:0}`)}catch(e){d.error("检查队列状态时出错:",e.message)}}getConfig(){return{autoReload:this.config.autoReload,isRunning:this.isRunning,intervalId:null!==this.intervalId}}},A=t;class AMQPInitializer{constructor(){this.configResolver=new f,this.connectionManager=null,this.messageProcessor=null,this.autoReloader=null,this.config=null}async init(e={}){try{this.config=this.configResolver.resolveConfig(e),A.log("配置解析完成");const t=await this.configResolver.resolveAmqpLink(this.config.amqpAutoLink,this.config.amqpLink);this.connectionManager=new M(this.config),this.messageProcessor=new y(this.config),this.autoReloader=new w(this.config),this.connectionManager.setAmqpLink(t);const s=await this.connectionManager.initialize();this._setupReconnectHandler(),await this.messageProcessor.startConsuming(s),A.log("消息处理器已启动"),this.autoReloader.start(s),this.config.finish(),A.log("AMQP初始化完成")}catch(e){throw A.error("AMQP初始化失败:",e.message),e}}_setupReconnectHandler(){const e=this.connectionManager.reconnect.bind(this.connectionManager);this.connectionManager.reconnect=async()=>{try{const t=await e();return this.messageProcessor.clearProcessingMessages(),await this.messageProcessor.startConsuming(t),A.log("重连后消息处理器已重新启动"),this.autoReloader.restart(t),A.log("重连后自动重载监控已重新启动"),t}catch(e){throw A.error("重连处理失败:",e.message),e}}}getStatus(){return{isConnected:!!this.connectionManager&&this.connectionManager.isConnected(),processingCount:this.messageProcessor?this.messageProcessor.getProcessingCount():0,autoReloaderActive:!!this.autoReloader&&this.autoReloader.isActive(),channelName:this.config?this.config.channelName:null}}async shutdown(){try{A.log("开始优雅关闭AMQP连接..."),this.autoReloader&&this.autoReloader.stop(),this.messageProcessor&&this.messageProcessor.clearProcessingMessages(),this.connectionManager&&await this.connectionManager.close(),A.log("AMQP连接已优雅关闭")}catch(e){A.error("关闭AMQP连接时出错:",e.message)}}}return i({async init(e){const t=new AMQPInitializer;return await t.init(e)},AMQPInitializer:AMQPInitializer})});
1
+ !function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t(require("axios"),require("chalk-style"),require("amqplib"),require("happy-help")):"function"==typeof define&&define.amd?define(["axios","chalk-style","amqplib","happy-help"],t):(e="undefined"!=typeof globalThis?globalThis:e||self).AmqplibInit=t(e.require$$0,e.require$$1,e.require$$0$1,e.require$$2)}(this,function(e,t,s,n){"use strict";function i(e){return e&&e.__esModule&&Object.prototype.hasOwnProperty.call(e,"default")?e.default:e}const o=e,c=t;var a=class{constructor(){this.defaultConfig={channelName:"node-test-channel",prefetch:1,callback:()=>{},finish:()=>{},amqpLink:"",amqpAutoLink:"",heartbeat:60,timeout:3e5,delay:0,autoReload:0,queryHook:()=>{},initHook:()=>{},durable:!0,messageTimeout:9e5,reconnectDelay:5e3,maxReconnectAttempts:10}}resolveConfig(e={}){return{...this.defaultConfig,...e}}async resolveAmqpLink(e,t){if(!e)return t;try{c.log(`正在从 ${e} 获取连接信息...`);const s=await o.post(e),{info:n}=s.data;if(this._validateConnectionInfo(n)){const e=`amqp://${n.AMQPLIB_USER}:${n.AMQPLIB_PWD}@${n.AMQPLIB_PUB}:${n.AMQPLIB_PORT}`;return c.log(`✅ 自动获取连接信息成功: ${e}`),e}return c.error("❌ 获取的连接信息不完整,使用默认连接地址"),t}catch(e){return c.error("❌ 获取连接信息失败:",e.message),c.log("使用默认连接地址继续..."),t}}_validateConnectionInfo(e){return e&&e.AMQPLIB_USER&&e.AMQPLIB_PWD&&e.AMQPLIB_PUB&&e.AMQPLIB_PORT}};const r=s,h=t,l=n;var g=class{constructor(e){this.config=e,this.connection=null,this.channel=null,this.amqpLink="",this.reconnectInProgress=!1,this.reconnectAttempts=0,this.maxReconnectAttempts=e.maxReconnectAttempts||10}setAmqpLink(e){this.amqpLink=e}async initialize(){const{channelName:e,durable:t,prefetch:s,heartbeat:n,timeout:i,initHook:o,reconnectDelay:c}=this.config;try{return this.connection=await r.connect(this.amqpLink,{heartbeat:n,timeout:i}),this.channel=await this.connection.createChannel(),await this.channel.assertQueue(e,{durable:t}),await this.channel.prefetch(s),await o({channel:this.channel,connection:this.connection}),h.log(`已连接到RabbitMQ,频道: ${e}`),this._setupConnectionEvents(),this.channel}catch(e){throw h.error("初始化RabbitMQ连接时出错:",e),e}}async reconnect(){if(this.reconnectInProgress)return h.log("重连已在进行中,跳过此次重连请求"),this.channel;if(this.reconnectAttempts>=this.maxReconnectAttempts)return h.error(`❌ 已达到最大重连次数 ${this.maxReconnectAttempts},停止重连`),h.error("请检查 RabbitMQ 服务状态或网络连接"),null;this.reconnectInProgress=!0,this.reconnectAttempts++;try{h.error(`🔄 连接丢失,正在尝试第 ${this.reconnectAttempts}/${this.maxReconnectAttempts} 次重连...`),await this._cleanupOldChannel();const e=(this.config.reconnectDelay||5e3)/1e3;return await l.sleep(e),await this.initialize(),this.reconnectAttempts=0,h.log(`✅ 已重新连接到RabbitMQ,频道: ${this.config.channelName}`),this.channel}catch(e){if(h.error(`❌ 第 ${this.reconnectAttempts} 次重连失败:`,e.message),this.reconnectAttempts<this.maxReconnectAttempts){const e=this.config.reconnectDelay||5e3;setTimeout(()=>{this.reconnectInProgress=!1,this.reconnect()},e)}else h.error("❌ 已达到最大重连次数,停止重连");throw e}finally{this.reconnectInProgress=!1}}getChannel(){return this.channel}getConnection(){return this.connection}isConnected(){return this.connection&&this.channel&&!this.connection.connection.destroyed}async close(){try{this.channel&&(await this.channel.close(),this.channel=null),this.connection&&(await this.connection.close(),this.connection=null),h.log("RabbitMQ连接已关闭")}catch(e){h.error("关闭连接时出错:",e.message)}}_setupConnectionEvents(){this.connection.on("error",e=>{h.error("连接错误:",e.message),this.reconnect().catch(e=>{h.error("重连失败:",e.message)})}),this.connection.on("close",()=>{h.error("与RabbitMQ的连接已关闭"),this.reconnect().catch(e=>{h.error("重连失败:",e.message)})})}async _cleanupOldChannel(){if(this.channel){try{await this.channel.close()}catch(e){h.log("关闭旧channel时出错:",e.message)}this.channel=null}}getStats(){return{isConnected:this.isConnected(),reconnectAttempts:this.reconnectAttempts,maxReconnectAttempts:this.maxReconnectAttempts,reconnectInProgress:this.reconnectInProgress}}};const u=t,m=n;var p=class{constructor(e){this.config=e,this.processingMessages=new Set}async startConsuming(e){const{channelName:t,callback:s,delay:n}=this.config;return u.log(`开始消费: ${t}`),await e.consume(t,async t=>{null!==t?this._handleMessage(t,e,s,n).catch(e=>{u.error("处理消息时发生未捕获异常:",e)}):u.log("收到null消息,队列可能为空或连接中断")},{noAck:!1}),()=>{this.processingMessages.clear(),u.log("已清理消息处理状态")}}async _handleMessage(e,t,s,n){const i=e.fields.deliveryTag;if(this.processingMessages.has(i))u.log(`消息 ${i} 已在处理中,跳过`);else{if(this.processingMessages.add(i),!this._isValidMessageContent(e))return u.log(`⚠️ 收到无效消息 ${i},内容为空或无法解析,自动确认以防止阻塞`),void this._acknowledgeMessage(e,t,i,0);try{const o=JSON.parse(e.content.toString());u.log(`🪴 队列收到消息: ${JSON.stringify(o)}`);const c=Date.now(),a=new Promise((e,t)=>{setTimeout(()=>{t(new Error(`消息处理超时 (${this.config.messageTimeout}ms)`))},this.config.messageTimeout)});try{await Promise.race([s(o),a]);const r=Date.now()-c;u.log(`☘️ 消息处理完成,延迟: ${n}ms,总时间: ${r}ms`),this._acknowledgeMessage(e,t,i,n)}catch(s){s.message.includes("超时")?u.error(`⏰ 消息 ${i} 处理超时 (${this.config.messageTimeout}ms)`):u.log("‼️ 处理消息返回错误:",s.message),await this._rejectMessage(e,t,i)}}catch(s){u.log("‼️ 处理消息时出错:",s.message),await this._rejectMessage(e,t,i)}}}_isValidMessageContent(e){try{if(!e||!e.content)return!1;const t=e.content.toString();return!(!t||""===t.trim())&&("null"!==t.toLowerCase()&&"undefined"!==t.toLowerCase()&&(JSON.parse(t),!0))}catch(e){return!1}}_acknowledgeMessage(e,t,s,n){this.processingMessages.has(s)&&setTimeout(()=>{try{t.ack(e),this.processingMessages.delete(s),u.log(`✅ 消息 ${s} 已确认`)}catch(e){u.error(`ACK消息 ${s} 时出错:`,e.message),this.processingMessages.delete(s)}},n)}async _rejectMessage(e,t,s){if(await m.sleep(5),this.processingMessages.has(s))try{t.reject(e,!0),this.processingMessages.delete(s),u.log(`❌ 消息 ${s} 已拒绝并重新排队`)}catch(e){u.error(`拒绝消息 ${s} 时出错:`,e.message),this.processingMessages.delete(s)}}clearProcessingMessages(){this.processingMessages.clear(),u.log("已清理所有消息处理状态")}getProcessingCount(){return this.processingMessages.size}};const d=t;const f=a,M=g,y=p,w=class{constructor(e){this.config=e,this.intervalId=null,this.isRunning=!1}start(e){const{autoReload:t,channelName:s,queryHook:n}=this.config;t<=0?d.log("自动重载功能未启用"):this.isRunning?d.log("自动重载监控已在运行中"):(this.isRunning=!0,d.log(`启动队列监控,间隔: ${t}ms`),this.intervalId=setInterval(async()=>{try{await this._checkQueueStatus(e,s,n)}catch(e){d.error("队列状态检查时出错:",e.message)}},t))}stop(){this.intervalId&&(clearInterval(this.intervalId),this.intervalId=null,this.isRunning=!1,d.log("自动重载监控已停止"))}restart(e){this.stop(),this.start(e)}isActive(){return this.isRunning}async _checkQueueStatus(e,t,s){try{const{messageCount:n}=await e.checkQueue(t),i=await s();d.log(`队列 ${t} 中有 ${n} 条消息,钩子状态: ${i?1:0}`)}catch(e){d.error("检查队列状态时出错:",e.message)}}getConfig(){return{autoReload:this.config.autoReload,isRunning:this.isRunning,intervalId:null!==this.intervalId}}},A=t;class AMQPInitializer{constructor(){this.configResolver=new f,this.connectionManager=null,this.messageProcessor=null,this.autoReloader=null,this.config=null}async init(e={}){try{this.config=this.configResolver.resolveConfig(e),A.log("配置解析完成");const t=await this.configResolver.resolveAmqpLink(this.config.amqpAutoLink,this.config.amqpLink);this.connectionManager=new M(this.config),this.messageProcessor=new y(this.config),this.autoReloader=new w(this.config),this.connectionManager.setAmqpLink(t);const s=await this.connectionManager.initialize();this._setupReconnectHandler(),await this.messageProcessor.startConsuming(s),A.log("消息处理器已启动"),this.autoReloader.start(s),this.config.finish(),A.log("AMQP初始化完成")}catch(e){throw A.error("AMQP初始化失败:",e.message),e}}_setupReconnectHandler(){const e=this.connectionManager.reconnect.bind(this.connectionManager);this.connectionManager.reconnect=async()=>{try{const t=await e();return this.messageProcessor.clearProcessingMessages(),await this.messageProcessor.startConsuming(t),A.log("重连后消息处理器已重新启动"),this.autoReloader.restart(t),A.log("重连后自动重载监控已重新启动"),t}catch(e){throw A.error("重连处理失败:",e.message),e}}}getStatus(){return{isConnected:!!this.connectionManager&&this.connectionManager.isConnected(),processingCount:this.messageProcessor?this.messageProcessor.getProcessingCount():0,autoReloaderActive:!!this.autoReloader&&this.autoReloader.isActive(),channelName:this.config?this.config.channelName:null}}async shutdown(){try{A.log("开始优雅关闭AMQP连接..."),this.autoReloader&&this.autoReloader.stop(),this.messageProcessor&&this.messageProcessor.clearProcessingMessages(),this.connectionManager&&await this.connectionManager.close(),A.log("AMQP连接已优雅关闭")}catch(e){A.error("关闭AMQP连接时出错:",e.message)}}}return i({async init(e){const t=new AMQPInitializer;return await t.init(e)},AMQPInitializer:AMQPInitializer})});
package/package.json CHANGED
@@ -1,6 +1,7 @@
1
1
  {
2
2
  "name": "amqplib-init",
3
- "version": "1.3.2",
3
+ "version": "1.3.4",
4
+ "type": "module",
4
5
  "description": "消息队列初始化 - 移除PM2依赖,改用Supervisor管理 (支持15分钟长任务)",
5
6
  "main": "dist/amqplib-init.cjs.js",
6
7
  "module": "dist/amqplib-init.esm.js",
@@ -49,4 +50,4 @@
49
50
  "@rollup/plugin-terser": "^0.4.4",
50
51
  "rollup": "^4.9.6"
51
52
  }
52
- }
53
+ }