egg-guardian
egg guardian plugin
Install
npm i egg-guardian
Usage
Simple - use default validator and interrupter
WorkerQpsJsonRule
Use Response 429 and JSON to client.
// config/config.default.js
module.exports = {
guardian: {
clients: {
http: {
rule: [ 'WorkerQpsJsonRule' ]
},
},
rules: {
WorkerQpsJsonRule: {
thresholdMap: {
// Define threshold one worker can handle
// Format is `${method}-${path}`
'POST-/foo/:id': 10,
'GET-/foo': 10,
},
// Json interrupter response content
responseContent: { msg: 'System is busy' },
// Json interrupter response status code
responseStatus: 429,
},
},
},
};
WorkerQpsRedirectRule
Use Redirect to specified url.
// config.default.js
module.exports = {
guardian: {
clients: {
http: {
rule: [ 'WorkerQpsRedirectRule' ]
},
},
rules: {
WorkerQpsRedirectRule: {
thresholdMap: {
// Define threshold one worker can handle
'POST-/foo/:id': 10,
'GET-/foo': 10,
},
// Redirect interrupter redirect url
redirectUrl: 'http://foo/server_busy',
},
},
},
};
WorkerQpsLogRule
.
Use Print guardian log.
// config.default.js
module.exports = {
guardian: {
clients: {
http: {
rule: [ 'WorkerQpsLogRule' ]
},
},
rules: {
WorkerQpsLogRule: {
thresholdMap: {
// Define threshold one worker can handle
'POST-/foo/:id': 10,
'GET-/foo': 10,
},
},
},
},
};
Advanced
GuardianLoader
egg-guardian
will load app/guardian/interrupter
to app.guardianInterrupters, load app/guardian/validator
to app.guardianInterrupters.
Loader case style is upper
, json_interrupter
will load to JsonInterrupter
.
DefaultInterrupter
JsonInterrupter
Interrupt request, response with JSON content, should set responseStatus
(default is 429), responseContent
in rule config.
LogInterrupter
Not interrupt request, just print log.
RedirectInterrupter
Interrupt request, redirect to redirectUrl
, should set redirectUrl
in rule Config.
DefaultValidator
WorkerQpsValidator
If qps is over threshold, mark request should not paas. Should set thresholdMap
in rule config.
- convert request to
requestKey
.GET /foo
map toGET-/foo
- plus
requestKey
qps. - compare qps with threshold
Define custom validator and interrupter.
- Define validator.
// guardian/validator/custom_validator.js
'use strict';
module.exports = app => {
class CustomValidator extends app.GuardianValidator {
/**
* @constructor
* @params {object} options -
* @params {Application} options.app -
* @params {object} config - rule config. `config.guardian.rules.rule`
*/
constructor(options) {
super(options);
this.counter = 0;
// ready(true) is required. Rule will wait to validator is ready.
this.ready(true);
}
/**
* validate before process request
* @param {Context} ctx -
* @return {Promise<Boolean>} request can be passed
*/
async preValidate(ctx) {
return true;
}
/**
* validate after process request
* @param {Context} ctx -
* @return {Promise<Boolean>} request can be passed
*/
async sufValidate() {
return this.counter++ % 2 === 0;
}
}
};
- Define interrupter.
// guardian/interrupter/custom_interrupter.js
'use strict';
module.exports = app => {
return class CustomInterrupter extends app.GuardianInterrupter {
/**
* @constructor
* @params {object} options -
* @params {Application} options.app -
* @params {object} config - rule config. `config.guardian.rules.rule`
*/
constructor(options) {
super(options);
// ready(true) is required. Rule will wait to interrupter is ready.
this.ready(true);
}
/**
* interrupt request
* @param {Context} ctx -
* @return {boolean} - should continue process
*/
async interrupt(ctx) {
ctx.status = 429;
return false;
}
};
};
- Define rule.
// config/config.default.js
module.exports = {
guardian: {
clients: {
http: {
// Use custom rule
rules: [ 'CustomRule' ],
},
},
rules: {
// Define custom rule
CustomRule: {
interrupter: 'CustomInterrupter',
validator: 'CustomValidator',
},
},
},
};