使用 nvm 和 pm2 的错误 运行 遗留 node.js 应用程序

Error running legacy node.js app with nvm and pm2

我的问题

我有一个 old nodejs 应用程序(运行s 在 v0.8.18 下!)我想保留 运行ning历史原因。我通常可以从命令行 运行 它(即 $ node app),但我不能通过 pm2 运行 它(即 $ pm2 start app)。

这是我的设置:

[{
  "name": "my-old-app",
  "exec_interpreter": "node@0.8.18",
  "script": "app.js",
  "error": "error.log"
}]
$ NVM_DIR=/home/myusername/.nvm/ pm2 start pm2.json

产量:

$ NVM_DIR=/home/myusername/.nvm/ pm2 start pm2.json
[PM2][WARN] Applications my-old-app not running, starting...
[PM2] Setting Node to v0.8.18 (path=/home/myusername/.nvm/v0.8.18/bin/node)
[PM2] App [my-old-app] launched (1 instances)
┌─────────────────┬────┬──────┬──────┬────────┬─────────┬────────┬─────┬──────────┬────────────┬──────────┐
│ App name        │ id │ mode │ pid  │ status │ restart │ uptime │ cpu │ mem      │ user       │ watching │
├─────────────────┼────┼──────┼──────┼────────┼─────────┼────────┼─────┼──────────┼────────────┼──────────┤
│ my-old-app      │ 0  │ fork │ 5879 │ online │ 0       │ 0s     │ 0%  │ 7.9 MB   │ myusername │ disabled │
└─────────────────┴────┴──────┴──────┴────────┴─────────┴────────┴─────┴──────────┴────────────┴──────────┘
 Use `pm2 show <id|name>` to get more details about an app

当我开始尝试以这种方式启动应用程序时,这是 运行ning pm2 show my-old-app

的结果
 Describing process with id 0 - name my-old-app
┌───────────────────┬──────────────────────────────────────────────────┐
│ status            │ errored                                          │
│ name              │ my-old-app                                       │
│ restarts          │ 15                                               │
│ uptime            │ 0                                                │
│ script path       │ /home/myusername/my-old-app/app.js               │
│ script args       │ N/A                                              │
│ error log path    │ /home/myusername/my-old-app/error-0.log          │
│ out log path      │ /home/myusername/.pm2/logs/my-old-app-out-0.log  │
│ pid path          │ /home/myusername/.pm2/pids/my-old-app-0.pid      │
│ interpreter       │ /home/myusername/.nvm/v0.8.18/bin/node           │
│ interpreter args  │ N/A                                              │
│ script id         │ 0                                                │
│ exec cwd          │ /home/myusername/my-old-app/                     │
│ exec mode         │ fork_mode                                        │
│ node.js version   │ N/A                                              │
│ watch & reload    │ ✘                                                │
│ unstable restarts │ 0                                                │
│ created at        │ N/A                                              │
└───────────────────┴──────────────────────────────────────────────────┘

此外,error-0.log中反复出现的错误是:

domain.js:66
    throw er;
          ^
TypeError: Object #<Object> has no method 'unref'
    at Object.PMX.init (/home/myusername/.nvm/versions/node/v9.3.0/lib/node_modules/pm2/node_modules/pmx/lib/pmx.js:81:8)
    at Object.<anonymous> (/home/myusername/.nvm/versions/node/v9.3.0/lib/node_modules/pm2/lib/ProcessContainerFork.js:8:18)
    at Module._compile (module.js:449:26)
    at Object.Module._extensions..js (module.js:467:10)
    at Module.load (module.js:356:32)
    at Function.Module._load (module.js:312:12)
    at Module.runMain (module.js:492:10)
    at process.startup.processNextTick.process._tickCallback (node.js:244:9)

I don't know why this doesn't work.

什么有效

如果我只是 运行 从命令行正常运行应用程序,它会按预期完美运行,即

$ nvm use 0.8.18
Now using node v0.8.18 (npm v1.2.2)
$ node app
   info  - socket.io started
Express server listening on port 37426

它通过 nginx 进行反向代理,并可通过 https://old.example.com 在浏览器中使用。仅供参考,我的 nginx 站点配置的内容:

server {
  listen 80;
  listen [::]:80;
  listen 443 ssl;
  ssl_certificate /etc/letsencrypt/live/old.example.com/fullchain.pem; # managed by Certbot
  ssl_certificate_key /etc/letsencrypt/live/old.example.com/privkey.pem; # managed by Certbot
  include /etc/letsencrypt/options-ssl-nginx.conf;

  server_name old.example.com;

  if ($scheme != "https") {
    return 301 https://$host$request_uri;
  }

  # Pass requests for / to localhost:37426:
  location / {
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-NginX-Proxy true;
    proxy_pass http://localhost:37426/;
    proxy_ssl_session_reuse off;
    proxy_set_header Host $http_host;
    proxy_cache_bypass $http_upgrade;
    proxy_redirect off;
  }
}

显然,我不能只使用此设置,因为如果进程因任何原因中断,它不会重新启动。有任何想法吗?我尝试 运行 将应用程序与节点 v9.3.0 连接起来,但代码太旧了。它也太广泛了,无法以更新的形式重写。

从错误日志来看,您似乎正在尝试 运行 使用节点 v9.3.0 的应用程序。

将你的命令修改成这样[未测试]

NVM_DIR=/home/myusername/.nvm/ nvm use 0.8.18 && pm2 start pm2.json

我明白了。 pm2 depends upon pmx, which in turn uses the setTimeout().unref() functionunref() 函数直到 v0.9.1 才被添加到 nodejs 中。由于我试图 运行 我的应用程序与节点 v0.8.18unref() 函数未定义因此出现 Object #<Object> has no method 'unref' 错误消息。

尝试 运行 我的应用程序在较新的节点版本下总是失败,但最终我意识到它总是因为同一个包而失败:bcrypt。事实证明,这个包的原始作者使用了一个奇怪的、有问题的中间版本 bcrypt (v0.7.5)。当我将其切换到稍新的 bcrypt (v0.7.6) 时,我能够 运行 具有节点 v0.9.12 的整个应用程序,这反过来又使其安全pm2 使用 unref().

总结...

  1. 不要尝试使用 pm2 尝试 运行 节点应用程序 <v0.9.1,或
  2. 如果这样做,您可能需要修改应用程序,使其可以 运行 与节点 >=v0.9.1

更新

pm2 的维护者之一让我知道 they don't officially support any versions of nodejs <v0.12 and soon they'll be dropping support for that as well