Nervous Parrot Muttering

    egg-schedule

    3.6.6 • Public • Published

    egg-schedule

    NPM version build status Test coverage David deps Known Vulnerabilities npm download

    A schedule plugin for egg, has been built-in plugin for egg enabled by default.

    It's fully extendable for a developer and provides a simple built-in TimerStrategy.

    Usage

    Just add your job file to {app_root}/app/schedule.

    // {app_root}/app/schedule/cleandb.js
    const Subscription = require('egg').Subscription;
     
    class CleanDB extends Subscription {
      /**
       * @property {Object} schedule
       *  - {String} type - schedule type, `worker` or `all` or your custom types.
       *  - {String} [cron] - cron expression, see [below](#cron-style-scheduling)
       *  - {Object} [cronOptions] - cron options, see [cron-parser#options](https://github.com/harrisiirak/cron-parser#options)
       *  - {String | Number} [interval] - interval expression in millisecond or express explicitly like '1h'. see [below](#interval-style-scheduling)
       *  - {Boolean} [immediate] - To run a scheduler at startup
       *  - {Boolean} [disable] - whether to disable a scheduler, usually use in dynamic schedule
       *  - {Array} [env] - only enable scheduler when match env list
       */
      static get schedule() {
        return {
          type: 'worker',
          cron: '0 0 3 * * *',
          // interval: '1h',
          // immediate: true,
        };
      }
     
      async subscribe() {
        await this.ctx.service.db.cleandb();
      }
    }
     
    module.exports = CleanDB;

    You can also use function simply like:

    exports.schedule = {
      type: 'worker',
      cron: '0 0 3 * * *',
      // interval: '1h',
      // immediate: true,
    };
     
    exports.task = async function (ctx) {
      await ctx.service.db.cleandb();
    };

    Overview

    egg-schedule supports both cron-based scheduling and interval-based scheduling.

    Schedule decision is being made by agent process. agent triggers a task and sends a message to worker process. Then, one or all worker process(es) execute the task based on schedule type.

    To setup a schedule task, simply create a job file in {app_root}/app/schedule. A file contains one job and exports schedule and task properties.

    The rule of thumbs is one job per file.

    Task

    Task is a class which will be instantiated with every schedule, and a subscribe method will be invoked.

    You can get anonymous context with this.ctx.

    • ctx.method: SCHEDULE
    • ctx.path: /__schedule?path=${schedulePath}&${schedule}.

    To create a task, subscribe can be a generator function or async function. For example:

    // A simple logger example
    const Subscription = require('egg').Subscription;
    class LoggerExample extends Subscription {
      async subscribe() {
        this.ctx.logger.info('Info about your task');
      }
    }
    // A real world example: wipe out your database.
    // Use it with caution. :)
    const Subscription = require('egg').Subscription;
    class CleanDB extends Subscription {
      async subscribe() {
        await this.ctx.service.db.cleandb();
      }
    }

    Scheduling

    schedule is an object that contains one required property, type, and optional properties, { cron, cronOptions, interval, immediate, disable, env }.

    Cron-style Scheduling

    Use cron-parser.

    Note: cron-parser support second as optional that is not supported by linux crontab.

    @hourly / @daily / @weekly / @monthly / @yearly is also supported.

    *    *    *    *    *    *
    ┬    ┬    ┬    ┬    ┬    ┬
    │    │    │    │    │    |
    │    │    │    │    │    └ day of week (0 - 7) (0 or 7 is Sun)
    │    │    │    │    └───── month (1 - 12)
    │    │    │    └────────── day of month (1 - 31)
    │    │    └─────────────── hour (0 - 23)
    │    └──────────────────── minute (0 - 59)
    └───────────────────────── second (0 - 59, optional)

    Example:

    // To execute task every 3 hours
    exports.schedule = {
      type: 'worker',
      cron: '0 0 */3 * * *',
      cronOptions: {
        // tz: 'Europe/Athens',
      }
    };

    Interval-style Scheduling

    To use setInterval, and support ms conversion style

    Example:

    // To execute task every 3 hours
    exports.schedule = {
      type: 'worker',
      interval: '3h',
    };

    Notice: Egg built-in TimerStrategy will schedule each execution at a fix rate, regardless of its execution time. So you have to make sure that your actual execution time of your task/subscribe must be smaller than your delay time.

    Schedule Type

    Build-in support is:

    • worker: will be executed in one random worker when a schedule runs.
    • all: will be executed in all workers when a schedule runs.

    Custom schedule:

    To create a custom schedule, simply extend agent.ScheduleStrategy and register it by agent.schedule.use(type, clz). You can schedule the task to be executed by one random worker or all workers with the built-in method this.sendOne(...args) or this.sendAll(...args) which support params, it will pass to subscribe(...args) or task(ctx, ...args).

    // {app_root}/agent.js
    module.exports = function(agent) {
      class CustomStrategy extends agent.ScheduleStrategy {
        start() {
          // such as mq / redis subscribe
          agent.notify.subscribe('remote_task', data => {
            this.sendOne(data);
          });
        }
      }
      agent.schedule.use('custom', CustomStrategy);
    };

    Then you could use it to defined your job:

    // {app_root}/app/schedule/other.js
    const Subscription = require('egg').Subscription;
    class ClusterTask extends Subscription {
      static get schedule() {
        return {
          type: 'custom',
        };
      }
      async subscribe(data) {
        console.log('got custom data:', data);
        await this.ctx.service.someTask.run();
      }
    }
    module.exports = ClusterTask;

    Dynamic schedule

    // {app_root}/app/schedule/sync.js
    module.exports = app => {
      class SyncTask extends app.Subscription {
        static get schedule() {
          return {
            interval: 10000,
            type: 'worker',
            // only start task when hostname match
            disable: require('os').hostname() !== app.config.sync.hostname,
            // only start task at prod mode
            env: [ 'prod' ],
          };
        }
        async subscribe() {
          await this.ctx.sync();
        }
      }
      return SyncTask;
    }

    Configuration

    Logging

    See ${appInfo.root}/logs/{app_name}/egg-schedule.log which provided by config.customLogger.scheduleLogger.

    // config/config.default.js
    config.customLogger = {
      scheduleLogger: {
        // consoleLevel: 'NONE',
        // file: path.join(appInfo.root, 'logs', appInfo.name, 'egg-schedule.log'),
      },
    };

    Customize directory

    If you want to add additional schedule directories, you can use this config.

    // config/config.default.js
    config.schedule = {
      directory: [
        path.join(__dirname, '../app/otherSchedule'),
      ],
    };

    Testing

    app.runSchedule(scheduleName) is provided by egg-schedule plugin only for test purpose.

    Example:

    it('test a schedule task', async function () {
      // get app instance
      await app.runSchedule('clean_cache');
    });

    Questions & Suggestions

    Please open an issue here.

    License

    MIT

    Install

    npm i egg-schedule

    DownloadsWeekly Downloads

    67,158

    Version

    3.6.6

    License

    MIT

    Unpacked Size

    31 kB

    Total Files

    14

    Last publish

    Collaborators

    • eggjs-admin
    • fengmk2
    • atian25
    • dead_horse
    • popomore
    • wanghx
    • hyj1991
    • killagu
    • coolme200
    • mansonchor.zzw
    • hubcarl