Nodejs crontab 无法执行 coffee 程序的问题

Nodejs crontab 无法执行 coffee 程序的问题

express框架下coffee程序:

http = require 'http'
EventEmitter = require('events').EventEmitter
exports.importRequestNumber = (db, datetime)->
  COL = db.collection 'requestData'
  em = new EventEmitter()
  process.nextTick ->
    em.emit 'query data'
  em.once '500', (err)->
    console.log 'Error in import_data: ' + err
    console.log err.stack
    return em.emit 'error', err
  em.once 'done', ->
    return em.emit 'end'
  em.once 'query data', ->
    body = ''
    reqGet = http.get "http://test.komoxo.com:5000/cut?date="+datetime,(response)->
      response.on 'data', (chunk)->
        body += chunk
      response.on 'end', ()->
        data = JSON.parse data
        em.emit 'update data', data
    reqGet.on 'error', (e)->
      em.emit '500', e
    reqGet.end()
  em.once 'update data', (data)->
    COL.update {date: datetime}, {$set: {count: data.data.a, total: data.data.n, placecount: data.data.c}}, {upsert: true}, (err)->
      if err
        em.emit '500', err
      em.emit 'done'

if !module.parent
  db = require('./db').defaultDb()
  argv = process.argv[2..]
  if argv[0]
    datetime = argv[0]
  l=exports.importRequestNumber db, datetime
  l.once 'error', ->
    process.exit -1
  l.once 'end', ->
    process.exit 0

直接用coffee命令执行程序没问题,但在crontab下执行报错

crontab 环境变量已设置 运行程序,http.get请求时报

Failed to load c++ bson extension, using pure JS version (这个警告应该没影响的。。。)
Error in import_data: Error: connect ECONNREFUSED
Error: connect ECONNREFUSED
  at errnoException (net.js:646:11)
  at Object.afterConnect [as oncomplete] (net.js:637:18)

不知道,哪位大神遇到过类似问题,跪求帮助啊。。。


5 回复

Nodejs crontab 无法执行 coffee 程序的问题

问题描述

在使用 Express 框架下 CoffeeScript 编写的程序中,通过 coffee 命令直接执行程序时没有问题,但在 crontab 下执行时报错。错误信息显示 http.get 请求失败,并且有连接被拒绝的错误。

错误信息

Failed to load c++ bson extension, using pure JS version (这个警告应该没影响的。。。)
Error in import_data: Error: connect ECONNREFUSED
Error: connect ECONNREFUSED
  at errnoException (net.js:646:11)
  at Object.afterConnect [as oncomplete] (net.js:637:18)

解决方案

1. 设置正确的环境变量

确保 crontab 中设置了正确的环境变量。例如,可以将 PATH 和其他必要的环境变量添加到 crontab 中:

PATH=/usr/local/bin:/usr/bin:/bin
* * * * * cd /path/to/your/project && coffee your_script.coffee
2. 使用绝对路径

确保 coffee 命令使用的是绝对路径。可以在 crontab 中指定完整的路径:

* * * * * cd /path/to/your/project && /usr/local/bin/coffee your_script.coffee
3. 检查网络连接

connect ECONNREFUSED 错误通常表示目标服务器不可达。确保 http.get 请求的目标 URL 可以访问。你可以在本地环境中手动测试该 URL 是否可达。

4. 示例代码

假设你的脚本文件名为 import_request_number.coffee,你可以尝试以下 crontab 配置:

PATH=/usr/local/bin:/usr/bin:/bin
* * * * * cd /path/to/your/project && /usr/local/bin/coffee import_request_number.coffee $(date +%Y-%m-%d)

这里使用了 $(date +%Y-%m-%d) 来传递当前日期作为参数给脚本。

代码解析

以下是你的 CoffeeScript 代码的简化版本,展示了如何处理 HTTP 请求并更新数据库:

http = require 'http'
EventEmitter = require('events').EventEmitter

exports.importRequestNumber = (db, datetime) ->
  COL = db.collection 'requestData'
  em = new EventEmitter()
  
  process.nextTick ->
    em.emit 'query data'
  
  em.once '500', (err) ->
    console.log 'Error in import_data: ' + err
    console.log err.stack
    em.emit 'error', err
  
  em.once 'done', ->
    em.emit 'end'
  
  em.once 'query data', ->
    body = ''
    reqGet = http.get "http://test.komoxo.com:5000/cut?date=#{datetime}", (response) ->
      response.on 'data', (chunk) ->
        body += chunk
      response.on 'end', ->
        data = JSON.parse(body)
        em.emit 'update data', data
    
    reqGet.on 'error', (e) ->
      em.emit '500', e
    
    reqGet.end()
  
  em.once 'update data', (data) ->
    COL.update { date: datetime }, { $set: { count: data.data.a, total: data.data.n, placecount: data.data.c } }, { upsert: true }, (err) ->
      if err
        em.emit '500', err
      em.emit 'done'

if !module.parent
  db = require('./db').defaultDb()
  argv = process.argv[2..]
  datetime = argv[0] if argv[0]
  l = exports.importRequestNumber db, datetime
  l.once 'error', ->
    process.exit -1
  l.once 'end', ->
    process.exit 0

总结

通过确保 crontab 中的环境变量正确设置、使用绝对路径以及检查网络连接,你应该能够解决在 crontab 下执行 CoffeeScript 程序时遇到的问题。如果问题仍然存在,请进一步检查目标服务器是否可访问,并确保所有依赖项都已正确安装。


我随便猜测一下,会不会跟监听的端口有关呢?

这个问题跟 crontab 和 coffee 都没有关系吧? 做爬虫的时候,考虑一下远端服务器的防爬策略

首先你得确定这个错误是来自query data的阶段还是update data的阶段,我怀疑是在update data阶段出错的。

有无可能是那个db对象打开了一个socket连接数据库服务器,但是在任务完成后,就直接process.exit 0了,导致这个socket被占用。 因此,再次运行这个程序时,就被拒绝连接了。

从错误信息来看,问题可能出在环境变量或者网络连接上。ECONNREFUSED 错误表示连接被拒绝,可能是由于 http.get 请求的目标服务器未运行或无法访问。

解决步骤

  1. 检查目标URL是否可访问: 在你的环境中手动测试该URL是否能正常访问。可以使用 curl 或浏览器访问 http://test.komoxo.com:5000/cut?date=<datetime> 来确认。

  2. 确保环境变量正确配置: 确认 crontab 中 Node.js 和 CoffeeScript 的路径配置正确。可以在 crontab 文件中添加以下内容来设置环境变量:

    * * * * * export PATH=/usr/local/bin:/usr/bin:$PATH; coffee /path/to/your/file.coffee <datetime>
    
  3. 检查网络权限: 确保 crontab 脚本中的 Node.js 进程有权限访问外部网络。有时 crontab 运行的进程可能会受到防火墙或安全策略的限制。

示例 crontab 配置

假设你的脚本位于 /home/user/scripts/import.coffee,你可以这样配置 crontab:

* * * * * export PATH=/usr/local/bin:/usr/bin:$PATH; coffee /home/user/scripts/import.coffee $(date +%Y-%m-%d)

示例代码修正

为了更好地调试,可以修改代码以记录更多日志信息:

http = require 'http'
EventEmitter = require('events').EventEmitter

exports.importRequestNumber = (db, datetime) ->
  COL = db.collection 'requestData'
  em = new EventEmitter()
  
  # 添加日志记录
  console.log "Starting request for datetime: #{datetime}"
  
  process.nextTick ->
    em.emit 'query data'
    
  em.once '500', (err) ->
    console.error 'Error in import_data:', err
    console.error err.stack
    return em.emit 'error', err
    
  em.once 'done', ->
    return em.emit 'end'
    
  em.once 'query data', ->
    body = ''
    reqGet = http.get "http://test.komoxo.com:5000/cut?date=#{datetime}", (response) ->
      response.on 'data', (chunk) ->
        body += chunk
        
      response.on 'end', () ->
        try
          data = JSON.parse(body)
          em.emit 'update data', data
        catch e
          em.emit '500', e
          
    reqGet.on 'error', (e) ->
      console.error "Error in http.get:", e
      em.emit '500', e
      
    reqGet.end()
    
  em.once 'update data', (data) ->
    try
      COL.update {date: datetime}, {$set: {count: data.data.a, total: data.data.n, placecount: data.data.c}}, {upsert: true}, (err) ->
        if err
          em.emit '500', err
        em.emit 'done'
    catch e
      em.emit '500', e

总结

确保你的 crontab 脚本正确设置了环境变量,并且目标URL可访问。通过增加日志记录可以帮助你更好地诊断问题。

回到顶部