egg定时任务

作者: mocept | 来源:发表于2018-03-27 14:06 被阅读0次

    代码地址 https://github.com/MoceptWeb/egg-schedule
    看之前确定至少了解了egg的文档了, 不然看下面是浪费时间哈

    egg定时任务

    很多情况我们需要去定时(或者就一次)执行某些脚本, 这个时候就可以利用egg的schedule功能了

    怎样写

    schedule

    • {app_root}/app/schedule.js
        // 通过 schedule 属性来设置定时任务的执行间隔等配置
      static get schedule() {
        return {
          interval: '5m', // 5 min间隔
          type: 'worker', // worker 类型:每台机器上只有一个 worker 会执行这个定时任务
        };
      }
      async subscribe() {
        this.ctx.logger.info('schedule updateOa2User begin')
        const res = await this.ctx.service.portal.oa.updateOa2User();
        this.ctx.logger.info('schedule updateOa2User finish')
      }
    

    启动时候自定决定启动哪些定时任务

    在get schedule() 中配置immediate:配置了该参数为 true 时,这个定时任务会在应用启动并 ready 后立刻执行一次这个定时任务

      app.beforeStart(async () => {
        // await app.runSchedule('updateOa2User');updatePortal2User
        await app.runSchedule('updatePortal2User');
      });
    
    

    service

    • {app_root}/app/service/portal/oa.js

    sqlserver 连接

    // helper.js 统一连接一个sqlserver connection
    const mssql = require('mssql')
    let pool = await mssql.connect(config)
    
    // app.js 连接错误的日志
      mssql.on('error', err => {
        console.log('database err', err)
        app.logger.error(err);
        // ... error handler
      })
    

    异步中的多个全部异步完成的操作

    • 例如对一个数据进行一个个的异步操作, 但是最后获取全部异步后的结果

    切忌不要在异步中做同步操作, 不然执行顺序很意外!!!

        async updateUser(oaUser) {
            const self = this;
            let promiseAll = [];
          // 设置promise对象,同步发请求
            oaUser.forEach(oa => {
              promiseAll.push(Promise.resolve(self.updateUserByName(oa)));
            });
            await Promise.all(promiseAll);
        }
    
    • {app_root}/app/service/portal/portal.js

    异步中的多个全部异步完成的操作

    如果需要一步步获取全部数据(这里是同步)后才要进行全部异步其他操作, 那么需要先将同步操作封装成promise支持异步操作

    async readLine(target) {
          let array = [];
          const self = this;
          const file = await new Promise(function (resolve, reject) {
            lineReader.eachLine(target, function(line, last) {
                // line.split(/\s/)[0]
                let data = line.split(/\s/)
                if(data[2]) {
                    array.push({
                        user_id: self.ctx.helper.trim(data[0], '"'),
                        mail: self.ctx.helper.trim(data[1], '"'),
                        user_center_id: self.ctx.helper.trim(data[2], '"'),
                    })
                }
    
                if(last) {
                    resolve(array)
                }
            })
          })
    
          return file;
    
      }
    
    // 使用
    const fileData = await this.readLine(target);
        let promiseAll = [];
        fileData.forEach(portal => {
          promiseAll.push(Promise.resolve(self.updateUserByPortalId(portal)));
        });
    await Promise.all(promiseAll);
    

    mysql

    • sql的占位符
     const res = await conn.query('update t_user set mail = ? where user_id = ?', [oaUser.email, user.user_id]);
    
    • sql的事务
        async sqlBeginTransaction() {
            const conn = await this.app.mysql.beginTransaction();
    
            try {
                const res = await conn.query('update t_user set mail = ? where user_id = ?', [oaUser.email, user.user_id]);
                if(res && res.affectedRows === 1) {
                   await conn.commit();
                } else if(res.affectedRows > 1){
                    // this.ctx.logger.error('')
                   await conn.rollback()                
                } else {
                    await conn.rollback()                
                }
            } catch (err) {
            // error, rollback
              await conn.rollback(); // rollback call won't throw err
              throw err;
            }
        }
    

    extend

    • {app_root}/app/extend/helper.js

    统一封装各种数据的连接和error信息

    test

    • {app_root}/app/test/service/portal/portal.test.js
      待完善

    单元测试说明

    config

    谨记更环境用的配置是不一样的

    单元测试用的是 config.unittest.js

    为什么这样写

    TODO 分析源码

    拓展和优化

    • 将service中的纯数据库封装到model
    • 基于redis的任务消息队列的优化
      不需要人工去进行开启任务
    • 编写egg-mssql连接sqlserver

    相关文章

      网友评论

        本文标题:egg定时任务

        本文链接:https://www.haomeiwen.com/subject/fazjcftx.html