You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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();
  });
}
原因分析
  1. Node.js事件循环闲置退出:Node.js进程会在事件循环中没有待处理异步任务时自动退出。本地终端运行时,TTY环境会维持事件循环的活跃状态;但Docker容器中,若没有持续的异步任务触发,事件循环进入闲置状态后,进程就会以代码0退出。
  2. 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在容器环境中的不确定性:

  1. 本地执行编译命令:tsc(确保项目中有tsconfig.json配置)
  2. 修改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ı

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.19 13:20:26