为什么NodeJS / restify服务器*很少*在接受时报告EPERM?

时间:2016-03-24 15:11:36

标签: javascript node.js http error-handling

我在NodeJS中运行一个restify服务器。在极少数情况下,大约0.05%的HTTPS请求会导致net.js报告以下错误:

Error: accept EPERM
    at exports._errnoException (util.js:742:11)
    at TCP.onconnection (net.js:1280:24)

HTTP请求没有什么特别之处。在报告此错误之前,服务器可能已经为数千个请求提供服务,甚至响应了数十个相同的请求。我无法找到有关服务器为什么可能为已成功接受连接几个小时的套接字生成EPERM错误的任何信息。

顺便说一下,这个错误发生在源代码的任何执行上下文之外。因此,EPERM不是关于访问文件或执行其他系统调用的代码。当新请求到达时以及调用代码之前,EPERM正在NodeJS TCP代码的深处发生。

首先,当错误发生时,它将导致NodeJS终止。所以我添加了代码来捕获应用程序级异常:

process.on("uncaughtException", onUncaughtException );

但由于我不知道为什么这个错误正在发生,所以根本不清楚什么是恢复过程。

不确定它是否重要,但这里有大部分与启动restify服务相关的代码:

var restify    = require("restify");
// skipping some other init code
// configuration data is read from a JSON file
var serverOptions = {
   name: configuration.server.name,
   version: configuration.server.version,
   formatters: {
      "application/json": jsonResponseFormatter,
      "text/html": textResponseFormatter
   },
   serverOptions.key: fs.readFileSync(configuration.server.sslKey),
   serverOptions.cert: fs.readFileSync(configuration.server.sslCert)
}
var server = restify.createServer( serverOptions );
// skipping middleware inits and URL registrations
server.listen(
     configuration.server.port, // using HTTPS 443
     configuration.server.serverip );

顺便说一句,我们正在运行旧版本的NodeJS:v0.11.13。我的长期计划是升级到最新的稳定版本,但我们可能无法更新几个月。

2 个答案:

答案 0 :(得分:1)

让我在这里留下我的解决方案,以防万一其他人在将来遇到同样的问题。

从技术上讲,我没有发现为什么发生此错误,但我确实找到了如何成功处理错误情况:陷阱和释放。该错误必须在应用程序级别被捕获,因为它是在我的源代码的任何try-catch上下文之外的net.js内生成的。因此,如果我没有捕获它,那么它将使我的应用程序崩溃。但错误是非致命的,似乎可以安全地忽略它。在测试中,即使发生此错误,套接字仍继续接收新连接。

process.on("uncaughtException", onUncaughtException );
function onUncaughtException(error) {
  // put some code here to log the error occurrence, then ...
  if( error.code==="EPERM" && error.syscall==="accept" ) {
     // non-fatal error: do nothing; just ignore this error
  }
  else {
    // handle other application errors here
  }
}

因此,虽然知道为什么服务器套接字偶尔会出现EPERM错误仍然很有趣,但现在我知道在发生错误时知道正确处理错误的方法。

答案 1 :(得分:0)

$ man 2 accept
...
In addition, Linux accept() may fail if:

EPERM  Firewall rules forbid connection.

说实话,我不完全确定什么类型的防火墙规则会导致此错误,我能想到的是,您可能有一条规则允许来自特定客户端的传入连接,但不允许传出数据到该客户端IP /网络/端口/...