Docker部署的ethers.js区块链监听应用无报错退出问题排查
问题
我开发了一个简单的WebSocket应用,使用ethers.js监听区块链事件,通过Infura的WebSocket Provider连接区块链。将应用Docker化后运行镜像,进程会存活3-5分钟,随后无任何错误或提示以代码0退出;但直接在终端用npx ts-node src/index.ts运行时,应用可永久正常运行。
Docker日志中会输出⛓️ [chain]: Started listening events,说明应用已成功启动。期间未捕获任何事件,并非因执行某操作导致退出;若在退出前快速发起交易,应用可成功捕获事件并继续运行一段时间。
相关代码
Dockerfile
FROM node:alpine WORKDIR /app COPY package.json . RUN npm install COPY . . CMD ["npx", "ts-node", "src/index.ts"]
index.ts
import { listenContractEvents } from './events'; listenContractEvents() .then(() => console.log('⛓️ [chain]: Started listening events')) .catch(console.log);
events.ts
const provider = new ethers.providers.WebSocketProvider( `wss://goerli.infura.io/ws/v3/${process.env.INFURA_API_KEY}` ); async function listenContractEvents() { const contract = new ethers.Contract( contractAddress, contractAbi, provider ); let userList: User[] = await contract.getUserList(); contract.on('Register', async () => { console.log('⛓️ [chain]: New user registered!'); userList = await contract.getUserList(); }); }
原因分析
- Node.js事件循环闲置退出:Node.js进程会在事件循环中没有待处理异步任务时自动退出。本地终端运行时,TTY环境会维持事件循环的活跃状态;但Docker容器中,若没有持续的异步任务触发,事件循环进入闲置状态后,进程就会以代码0退出。
- Infura WebSocket连接闲置断开:Infura的WebSocket连接如果长时间没有事件交互(包括心跳),会主动断开。断开后如果没有重连逻辑,应用的事件循环就没有了待处理任务,进而导致进程退出。
解决方案
方案1:保持事件循环活跃
在listenContractEvents函数末尾添加一个空定时器,让事件循环始终有任务待处理:
async function listenContractEvents() { // 原有代码逻辑... // 每分钟触发一次空操作,防止事件循环闲置 setInterval(() => {}, 60000); }
方案2:添加WebSocket重连与心跳机制
为WebSocketProvider添加重连逻辑和心跳包,确保连接持续活跃:
const provider = new ethers.providers.WebSocketProvider( `wss://goerli.infura.io/ws/v3/${process.env.INFURA_API_KEY}` ); // 监听连接断开事件,自动重新初始化连接并监听事件 provider._websocket.on('close', () => { console.log('⛓️ [chain]: WebSocket连接断开,正在重连...'); // 这里可以封装重连逻辑,比如重新调用listenContractEvents函数 }); // 每30秒发送一次心跳包,维持连接 setInterval(() => { if (provider._websocket.readyState === 1) { provider._websocket.ping(); } }, 30000);
方案3:编译后运行,避免ts-node的潜在问题
先本地编译TypeScript为JavaScript,再在Docker中运行编译后的文件,减少ts-node在容器环境中的不确定性:
- 本地执行编译命令:
tsc(确保项目中有tsconfig.json配置) - 修改Dockerfile:
FROM node:alpine WORKDIR /app COPY package.json . # 安装生产依赖,减少镜像体积 RUN npm install --production # 复制编译后的dist目录 COPY dist/ . CMD ["node", "index.js"]
内容的提问来源于stack exchange,提问作者Ahmet Yazıcı
相关产品推荐
相关产品推荐

