Egg: 运用egg写一个任务,任务停止node服务也停止

Created on 25 Mar 2018  ·  29Comments  ·  Source: eggjs/egg

通用需求

想要指定运行一个任务(不是定时任务, 人工可以重复任意时间执行, 但是需要用到egg相关的插件和service所以考虑使用egg; 就是运行一个脚本, 脚本结束node服务就结束

实际业务需求

现在的具体场景是, 我需要运行一个查询某个数据库数据, 并配合某个java后端实现一定的数据处理功能; 就是一个脚本

请问各路大神怎么设计

Most helpful comment

简单手写了个

// agent.js
module.exports = agent => {
  agent.messenger.on('egg-ready', () => {
    agent.redis.subscribe('task');
  });

  class RedisStrategy extends agent.ScheduleStrategy {
    start() {
      // 订阅其他的分布式调度服务发送的消息,收到消息后让一个进程执行定时任务
      agent.redis.on('message', (channel, message) => {
        if (channel === 'task') {
          this.sendOne(message);
        }
      });
    }
  }
  agent.schedule.use('redis', RedisStrategy);
};


// config.default.js
config.redis = {
  client: {},
  agent: true,
};

// app/schedule/task.js
module.exports = {
  schedule: {
    type: 'redis',
  },
  async task(ctx, message) {
    console.log(message);
  }
}

All 29 comments

你是想做 aws 的 lamda?

@popomore 个人还没想那么复杂, 现在的具体场景是, 我需要运行一个查询某个数据库数据, 并配合某个java后端实现一定的数据处理功能; 就是一个脚本

做一个服务一直跑在那里有什么问题么?反正没请求也不消耗多少资源

@atian25

  • 如果我用定时器任务
    那么我这个任务就需要间隔很长, 因为是要执行完一次如果有需要才要去执行第二次; 而且要执行第二次还得重启服务器开始出发定时任务, 现在是想指定某个任务立即执行 如果都放在定时任务里面, 无法决定执行哪个了
  • 如果在appbefore直接执行service里面的任务
    时间太长了, 官方也不建议这样用啊;

  • 最主要就是 能指定某个任务任意时间像执行脚本一样执行
    您说的服务器一直跑是没问题, 但是怎样指定任务任意时间执行呢

发一个 http 或一条消息通知,然后再执行一次即可。

@atian25

  • 这个应用我只打算进行某些事务处理, 不对外, 所以不搭建对外服务器
    即使搭建了对外服务器,http请求过来这边我是需要做一个耗时长的脚本处理, 到时候都会超时,随意这样不对
  • 您说的消息通知具体是怎样的

好像这个场景是任务队列吧?

@thonatos 对的

做过类似的场景是视频转码:

user(submit) -- http server(proxy) -- master(push || record) -- worker (receive || loop_pull)

之前一个预想是使用 http 接收 task 后使用 Egg{agent} 分发,这样就需要使用多进程模型。

就是 egg-schedule 的一个扩展策略即可,收到 redis 或 mq 消息后触发一次 schedule

我们其实可以开发一个 redis 的插件作为示例

嗯, schedule 扩展那块的文档可以补补

@popomore @atian25 谢谢你们的建议, 但是任务时间原因, 我这次只能先应用启动时主动触发一次任务, 但是后续再来触发任务我只能暂时先不管了。。。(重启再来一次任务, 主要是这次任务是一次性的,下次也不知道何时才会再触发。。。)

  • 持续关注下schedule再优化, 不然我这个需求。。。。

你有用到 redis 什么的么

@atian25 主项目中用到了, 但是当前这个目前只作为任务处理的项目没用

直接通过 redis list 就可以了。

Worker 体系跟 Egg 框架其实差距比较大的,可以考虑加强。

我这次只能先应用启动时主动触发一次任务, 但是后续再来触发任务我只能暂时先不管了。。。(重启再来一次任务, 主要是这次任务是一次性的,下次也不知道何时才会再触发。。。)

你这种做法还不如搞个 node 命令行,每次来调一下,不用起 server。

@popomore node egg可以直接运行一个service命令吗, 我一开始问的问题就是怎么直接运行一个脚本, 脚本结束就程序结束了, 最后问着问着跑偏了

可以考虑用test执行你的脚本。


zhennann
zhen.[email protected]
Github: https://github.com/zhennann/egg-born

在 2018年3月25日,下午6:26,mocept notifications@github.com 写道:

@popomore https://github.com/popomore node egg可以直接运行一个service命令吗, 我一开始问的问题就是怎么直接运行一个脚本, 脚本结束就程序结束了


You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub https://github.com/eggjs/egg/issues/2265#issuecomment-375959877, or mute the thread https://github.com/notifications/unsubscribe-auth/AXH6yWtOhz5lRgFb1gL3zqEwTWuG-QB7ks5th3C6gaJpZM4S6Chl.

@zhennann 请问单元测试时候怎么指定config用哪个配置文件

  1. 不建议用单元测试。
  2. 实在要走歪路的话:

    • egg-scripts start --workers=1

    • 然后在你的那个处理的最后面,process.kill(process.ppid, '-9')

  3. 我还是倾向于定时任务的扩展的方式,文档其实写的还算清楚了:https://eggjs.org/zh-cn/basics/schedule.html#%E6%89%A9%E5%B1%95%E5%AE%9A%E6%97%B6%E4%BB%BB%E5%8A%A1%E7%B1%BB%E5%9E%8B

简单手写了个

// agent.js
module.exports = agent => {
  agent.messenger.on('egg-ready', () => {
    agent.redis.subscribe('task');
  });

  class RedisStrategy extends agent.ScheduleStrategy {
    start() {
      // 订阅其他的分布式调度服务发送的消息,收到消息后让一个进程执行定时任务
      agent.redis.on('message', (channel, message) => {
        if (channel === 'task') {
          this.sendOne(message);
        }
      });
    }
  }
  agent.schedule.use('redis', RedisStrategy);
};


// config.default.js
config.redis = {
  client: {},
  agent: true,
};

// app/schedule/task.js
module.exports = {
  schedule: {
    type: 'redis',
  },
  async task(ctx, message) {
    console.log(message);
  }
}

@atian25 歪路方法中

2018-03-25 21:34:51,143 ERROR 10310 [app_worker] exit with code:1
internal/process.js:175
        throw new Error(`Unknown signal: ${sig}`);
        ^

Error: Unknown signal: -9

process.kill(process.ppid, 'SIGKILL')

@atian25
打算成功后就杀死这个定时任务。。。

  async subscribe() {
    const res = await this.ctx.service.shell.test.find({ a: 'ss' });
    // this.app.messenger.sendToApp('test_action', {s: 'sss'});
    process.kill(process.pid, 'SIGKILL')
  }
2018-03-25 22:10:09,315 ERROR 10652 nodejs.AppWorkerDiedError: [master] app_worker#1:10654 died (code: null, signal: SIGKILL, suicide: false, state: dead), current workers: []
    at Master.onAppExit (/Users/d.hilter/code/node/egg/egg-example/node_modules/egg-cluster/lib/master.js:387:21)
    at emitOne (events.js:115:13)
    at Master.emit (events.js:210:7)
    at Messenger.sendToMaster (/Users/d.hilter/code/node/egg/egg-example/node_modules/egg-cluster/lib/utils/messenger.js:122:17)
    at Messenger.send (/Users/d.hilter/code/node/egg/egg-example/node_modules/egg-cluster/lib/utils/messenger.js:87:12)
    at EventEmitter.cluster.on (/Users/d.hilter/code/node/egg/egg-example/node_modules/egg-cluster/lib/master.js:264:22)
    at emitThree (events.js:140:20)
    at EventEmitter.emit (events.js:216:7)
    at ChildProcess.worker.process.once (internal/cluster/master.js:169:13)
    at Object.onceWrapper (events.js:318:30)
name: 'AppWorkerDiedError'
pid: 10652

PPID

@atian25 ppid 这个东西log出来就是没有。。。我还以为你打错了
改了照样不行

Worker 体系跟 Egg 框架其实差距比较大的

能分享下见解吗

Was this page helpful?
0 / 5 - 0 ratings