Authored by TaoHuang

Merge branch 'master' into hotfix/11

# Conflicts:
#	app.js
Showing 100 changed files with 341 additions and 1 deletions

Too many changes to show.

To preserve performance only 100 of 100+ files are displayed.

... ... @@ -55,6 +55,10 @@ app.use(convert(body({
})));
app.use(mount('/', webApp));
require('./middleware/zookeeper')(app);
// SSR自适应降级监控
require('./apps/tasks/degrade-ssr-task')(app);
server.listen(port, () => {
console.log(`app started in ${port}`);
... ...
No preview for this file type
... ... @@ -76,9 +76,21 @@ const defaultDegrades = [
path: '/pc/close/risk',
name: '【开关】关闭 风控中间件'
},
{
path: '/pc/open/apmrisk',
name: '【开关】启用 apm 风控中间件'
},
//wap
{
path: '/wap/webapp/degrade',
name: '【开关】APP内嵌SSR页面是否降级'
},
{
path: '/wap/open/yoluck-down',
name: 'yoluck接口降级到老版'
},
{
path: '/wap/plustar/removeCollect',
name: '【移除】Plustar>>> 品牌收藏'
},
... ... @@ -149,7 +161,23 @@ const defaultDegrades = [
{
path: '/wap/close/risk',
name: '【开关】关闭 风控中间件'
}
},
{
path: '/wap/open/apmrisk',
name: '【开关】启用 apm 风控中间件'
},
{
path: '/wap/webapp/yoho-community-web-yoho-protocol',
name: '打开yoho-protocol'
},
{
path: '/wap/webapp/ios-async-js',
name: '打开ios async js'
},
{
path: '/wap/open/webperf',
name: '打开前端性能上报'
},
];
class Degrade extends Model {
... ...
const schedule = require('node-schedule');
const Operation = require('../logger/operation');
const _ = require('lodash');
const {DegradeServer} = require('../models');
const setter = require('../zookeeper/setter');
const {client} = require('../../lib/redis');
module.exports = (koaApp) => {
schedule.scheduleJob('* * * * * *', async () => {
const appsData = await client.getAsync('degradeSSRKeys');
const apps = JSON.parse(appsData || '[]');
let server = await DegradeServer.findOne({
type: 'qcloud'
});
_.forEach(apps, async app => {
try {
const zkDegradePath = `/wap/webapp/${app}-degrade`;
const degradeKey = `${app}:degradessr`;
const isDegradeKey = `${degradeKey}:isdegrade`;
const [degradeJson, isDegrade] = await Promise.all([client.getAsync(degradeKey), client.getAsync(isDegradeKey)]);
const zkIsDegrade = _.get(koaApp, `locals.wap.webapp.${app}-degrade`, false);
const degrades = JSON.parse(degradeJson || '[]');
if (!isDegrade && zkIsDegrade) { // isdegrade的redis key已过期,且没有触发限制刷新key过期时间,则降级开关关闭
setter(`${server.ip}:${server.port}`, zkDegradePath, 'false');
console.log('SSR降级恢复')
Operation.action({
_id: 0,
username: 'ssr-degrade'
}, 'SSR降级恢复', '降级恢复' , {app});
}
_.forEach(degrades, async item => {
const key = `${degradeKey}:${item.time}`;
const result = await client.getAsync(key);
if (item.time * item.tick < +result) { // 大于qps限制,降级
const degradeData = {
...item,
maxTick: +result
};
console.log('触发降级策略')
Operation.action({
_id: 0,
username: 'ssr-degrade'
}, 'SSR降级', '触发降级策略' ,`${isDegradeKey},${JSON.stringify(degradeData)}`);
client.setexAsync(isDegradeKey, item.delay * 60, JSON.stringify(degradeData));
client.delAsync(key);
setter(`${server.ip}:${server.port}`, zkDegradePath, 'true');
}
});
return new Promise(resolve => {
setTimeout(() => {
resolve();
}, 1000);
});
} catch (error) {
console.log(error);
}
});
});
}
\ No newline at end of file
... ...
const Router = require('koa-router');
const _ = require('lodash');
const md5 = require('md5');
const CDNCONFIG = require('../../../config/cdn_config');
let r = new Router();
const manifestPath = 'client/precache/statics/manifest.json';
const client = {
index: async(ctx, next) => {
await ctx.render('action/client-precache', {
manifestPath
});
},
save: async(ctx, next) => {
let files = ctx.request.body.files;
let lastRevision = ctx.request.body.lastRevision;
let trimFiles = [];
_.forEach(files, val => {
trimFiles.push(_.trim(val));
});
trimFiles = _.compact(_.uniq(trimFiles));
let revision = md5(trimFiles.join(','));
if (revision === lastRevision) {
return ctx.body = {
code: 400,
message: '请修改后再保存'
};
}
let readable = new Buffer.from(JSON.stringify({
files: trimFiles,
revision
}));
let config = _.cloneDeep(CDNCONFIG.main);
_.assign(config, {
key: manifestPath
});
let qnMain = require('../../../lib/qiniu')(config);
let upResult = await qnMain.uploadAsync(readable, {key: manifestPath});
if (upResult && upResult.url) {
return ctx.body = {
code: 200,
message: '修改成功',
data: {
url: upResult.url
}
};
} else {
return ctx.body = {
code: 400,
message: '修改失败'
};
}
}
}
r.get('/client', client.index);
r.post('/client/save', client.save);
module.exports = r;
... ...
const Router = require('koa-router');
const SsrDegradeModel = require('../models/ssrDegradeModel');
let r = new Router();
const ssrDegrade = {
async index(ctx, next) {
const ssrDegradeModel = new SsrDegradeModel();
const apps = await ssrDegradeModel.getApps();
return ctx.render('action/ssr_degrade', {
list: apps || []
});
},
async editPage(ctx, next) {
const ssrDegradeModel = new SsrDegradeModel();
const app = ctx.request.query.app;
if (!app) {
return ctx.render('action/ssr_degrade_edit', {
data: {}
});
}
const appData = await ssrDegradeModel.getApp(app);
return ctx.render('action/ssr_degrade_edit', {
data: appData
});
},
async edit(ctx, next) {
const ssrDegradeModel = new SsrDegradeModel();
const data = ctx.request.body;
if (!data.app || !Array.isArray(data.degrades)) {
return ctx.body = {
code: 400,
message: '参数错误'
};
}
const result = ssrDegradeModel.editApp(data);
if (result) {
return ctx.body = {
code: 200,
};
}
return ctx.body = {
code: 500,
message: '失败'
};
},
async delete(ctx, next) {
const ssrDegradeModel = new SsrDegradeModel();
const app = ctx.request.query.app;
if (!app) {
return ctx.body = {
code: 400,
message: '参数错误'
};
}
const result = ssrDegradeModel.deleteApp({app});
if (result) {
return ctx.body = {
code: 200,
};
}
return ctx.body = {
code: 500,
message: '失败'
};
}
};
r.get('/index', ssrDegrade.index);
r.get('/edit', ssrDegrade.editPage);
r.post('/edit', ssrDegrade.edit);
r.get('/delete', ssrDegrade.delete);
module.exports = r;
... ...
... ... @@ -47,6 +47,7 @@ const mastersUrl = [
// 服务器监控数据采集
// collectData.collect();
app.use(async(ctx, next) => {
ctx.redis = redis.client;
... ...
const model = require('../../../lib/model');
const {client} = require('../../../lib/redis');
const ZookeeperModel = require('../../web/models/zookeeperModel');
const _ = require('lodash');
class SsrDegradeModel extends model {
constructor(ctx) {
super(ctx);
}
async getApps() {
const appsData = await client.getAsync('degradeSSRKeys');
const apps = JSON.parse(appsData || '[]');
return Promise.all(_.map(apps, this.getApp));
}
async getApp(app) {
const zookeeperModel = new ZookeeperModel();
const [degradeJson, isDegradeJson] = await Promise.all([
client.getAsync(`${app}:degradessr`),
client.getAsync(`${app}:degradessr:isdegrade`)]
);
const zkIsDegrade = await zookeeperModel.getPath(`/wap/webapp/${app}-degrade`);
const degrades = JSON.parse(degradeJson || '[]');
let isDegrade;
if (isDegradeJson) {
isDegrade = JSON.parse(isDegradeJson);
_.forEach(degrades, d => {
if (d.time === isDegrade.time && d.tick === isDegrade.tick) {
d.status = true;
d.maxTick = d.maxTick;
}
})
}
return {
app,
degrades,
status: zkIsDegrade === 'true'
};
}
async editApp(data) {
const zookeeperModel = new ZookeeperModel();
const appsData = await client.getAsync('degradeSSRKeys');
const apps = JSON.parse(appsData || '[]');
if (!apps.some(app => app === data.app)) {
apps.push(data.app);
client.setAsync('degradeSSRKeys', JSON.stringify(apps));
}
zookeeperModel.setPath(`/wap/webapp/${data.app}-degrade`, false);
client.delAsync(`${data.app}:degradessr:isdegrade`);
const degrades = _.map(data.degrades, d => {
return {
time: d.time,
tick: d.tick,
delay: d.delay
}
})
return await client.setAsync(`${data.app}:degradessr`, JSON.stringify(degrades));
}
async deleteApp(data) {
const zookeeperModel = new ZookeeperModel();
const appsData = await client.getAsync('degradeSSRKeys');
const apps = JSON.parse(appsData || '[]');
const saveApps = apps.filter(app => app !== data.app);
client.setAsync('degradeSSRKeys', JSON.stringify(saveApps));
client.delAsync(`${data.app}:degradessr`);
client.delAsync(`${data.app}:degradessr:isdegrade`);
zookeeperModel.setPath(`/wap/webapp/${data.app}-degrade`, false);
return true;
}
}
module.exports = SsrDegradeModel;
... ...
... ... @@ -11,6 +11,7 @@ const monitor = require('./actions/monitor');
const users = require('./actions/users');
const hotfix = require('./actions/hotfix');
const operationLog = require('./actions/operation_log');
const clientPrecache = require('./actions/client-precache');
const pageCache = require('./actions/page_cache');
const cdnCache = require('./actions/cdn_cache');
const productCache = require('./actions/product_cache');
... ... @@ -29,6 +30,7 @@ const noAuth = new Router();
const base = new Router();
const file = require('./actions/file');
const riskManagement = require('./actions/risk_management');
const ssrDegrade = require('./actions/ssr_degrade');
const logs = require('./actions/logs');
const spa = require('./actions/spa');
const upload = require('./actions/upload');
... ... @@ -56,6 +58,7 @@ module.exports = function(app) {
base.use('/monitor', monitor.routes(), monitor.allowedMethods());
base.use('/users', users.routes(), users.allowedMethods());
// base.use('/hotfix', hotfix.routes(), hotfix.allowedMethods());
base.use('/precache', clientPrecache.routes(), clientPrecache.allowedMethods());
base.use('/operation', operationLog.routes(), operationLog.allowedMethods());
base.use('/check', checkcode.routes(), checkcode.allowedMethods());
base.use('/page_cache', pageCache.routes(), pageCache.allowedMethods());
... ... @@ -80,6 +83,7 @@ module.exports = function(app) {
// base.use('', index.routes(), index.allowedMethods());
base.use('/risk_management', riskManagement.routes(), riskManagement.allowedMethods());
base.use('/ssr_degrade', ssrDegrade.routes(), ssrDegrade.allowedMethods());
base.use('/logs', logs.routes(), logs.allowedMethods());
base.use('/upload', upload.routes(), upload.allowedMethods());
base.use('', spa.routes(), spa.allowedMethods());
... ...