egg-schedule
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
.
const Subscription = require('egg').Subscription;
class CleanDB extends Subscription {
static get schedule() {
return {
type: 'worker',
cron: '0 0 3 * * *',
};
}
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 * * *',
};
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:
const Subscription = require('egg').Subscription;
class LoggerExample extends Subscription {
async subscribe() {
this.ctx.logger.info('Info about your task');
}
}
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:
exports.schedule = {
type: 'worker',
cron: '0 0 */3 * * *',
cronOptions: {
}
};
Interval-style Scheduling
To use setInterval
, and support ms conversion style
Example:
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)
.
module.exports = function(agent) {
class CustomStrategy extends agent.ScheduleStrategy {
start() {
agent.notify.subscribe('remote_task', data => {
this.sendOne(data);
});
}
}
agent.schedule.use('custom', CustomStrategy);
};
Then you could use it to defined your job:
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
module.exports = app => {
class SyncTask extends app.Subscription {
static get schedule() {
return {
interval: 10000,
type: 'worker',
disable: require('os').hostname() !== app.config.sync.hostname,
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.customLogger = {
scheduleLogger: {
},
};
Customize directory
If you want to add additional schedule directories, you can use this config.
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 () {
await app.runSchedule('clean_cache');
});
Questions & Suggestions
Please open an issue here.
License
MIT