Files
vic-server-mongo/src/jobs/jobs.js
2019-09-29 23:10:13 +08:00

188 lines
6.4 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
'use strict';
/**
* 为何要把分属于不同业务模块的job集中到此处
* 如果后续要把任务执行与web服务器分离就会很方便就算不分离也没多大坏处。
* 任务包括:
* transaction : {
* 1. 每小时去清理指定startTime的地产
* {
* status: -> 1,
* price: -> price * (1 + profit),
* currentOwner -> ''
* }
* 2. 将currentOwner对应的用户的asset.log加上a
* }
*/
const mongoose = require('mongoose');
const User = require('../modules/user/user.model');
const Fund = require('../modules/fund/fund.model');
const Action = require('../modules/action/action.model');
const system = require('../modules/system/system.model');
const { createAction } = require('../modules/action/action.handler');
const { createNewFund } = require('../modules/fund/fund.handler');
const tokenReleaseRate = 0.02;
async function awardMine(user, fund) {
if (!user || !fund || fund.fundList.length === 0) return 0;
let sum = 0;
for (let i = 0, len = fund.fundList.length; i < len; ++i) {
const released = fund.releasedAmout || 0;
if (released === fund.releasedAmout) {
await Fund.findByIdAndUpdate(fund.id, {
$set: {
[`fundList.${i}.status`]: 2 //标记失效
}
});
return 0;
}
sum += +fund.fundList[i].amount * tokenReleaseRate;
}
return sum;
}
function awardInvite(user, fund, allInviteReward) {
const rewardInvite = allInviteReward - (fund.option && fund.option.usedGroupReward || 0); // 求增量: 总额 - 已领取总额(fundSum)
// 挖矿奖励 = 充值金额奖励 + 社区奖励
return rewardInvite;
}
// fund.option.usedGroupReward : 已领取的社群奖励总额
const doReward = async (user, fund) => {
// 1.对于充值的fundList的每一项按照2%进行发放累加到asset.vic添加action类型为1
// 2.对于社团成员进行人头数目按照10vic/人进行奖励累加到asset.vic添加action类型为2
if (!user || !fund) return 0;
const allInviteReward = (+user.group.length || 0) * 10;
const rewardMine = await awardMine(user, fund);
const rewardInvite = awardInvite(user, fund, allInviteReward);
const reward = rewardMine + rewardInvite;
reward && await Fund.findByIdAndUpdate(fund.id, {
$inc: {
'asset.vic': reward,
},
$set: {
'option.usedGroupReward': rewardInvite, // 本次的奖励值累加到已领取团队奖励总和内
'asset.usdt': allInviteReward, // 用来记录所有社群奖励总额
'lastMine': new Date().toISOString()
}
}).then(() => {
rewardMine > 0 && createAction(1, {
userId: user.id,
tokenType: 'vic',
amount: rewardMine,
remain: fund.asset
}).save();
rewardInvite > 0 && createAction(2, {
userId: user.id,
tokenType: 'vic',
amount: rewardInvite,
remain: fund.asset
}).save();
});
};
const mock = {
touch: () => {console.log('touch');},
done: () => {console.log('done');},
};
async function mine (job = mock, done = mock) {
//todo: 程序内检查是否可以执行,保证不会启动时错误的自动执行一次
mylog.info('[Schedule Job] 挖矿程序 开始定时计算作业...');
let currentIndex = await system.findOne({
key: 'userIndex4job'
}).exec();
currentIndex = currentIndex.value;
if (typeof currentIndex !== 'number') {
currentIndex = 0;
await new system({
key: 'userIndex4job',
value: currentIndex
}).save();
}
// 批量更新,每次十个
const userFundList = await Fund.find().sort('_id').limit(10).skip(currentIndex);
// job.touch();
mylog.info('touch');
if (!userFundList || !Array.isArray(userFundList)) return 0;
for (let i = 0, len = userFundList.length; i < len; ++i) {
const fund = userFundList[i]; // 一条数据库fund表记录
if (fund.lastMine && new Date(fund.lastMine).getDate() === new Date().getDate()) {
mylog.info('已经计算过...跳过');
continue;
}
const user = await User.findById(fund.userId).exec();
await doReward(user, fund);
// job.touch();
await system.updateOne({ key: 'userIndex4job' }, {
$set: {
value: currentIndex
}
});
}
mylog.info('收益计算分配完成');
// done('收益计算分配完成');
}
async function confirm (job = mock, done = mock) {
mylog.info('[Schedule Job] 矿晶确认程序开始执行......');
const unconfirmed = await Fund.find({
'fundList.status': 0
});
mylog.info('共有' + unconfirmed.length + '用户需要确认');
unconfirmed.forEach(async (fund) => {
const len = fund.fundList.length || 0;
let acc = 0;
for (let i = 0; i < len; ++i) {
const fundItem = fund.fundList[i];
if (fundItem && fundItem.status === 0) {
++acc;
await Fund.findByIdAndUpdate(fund.id, {
$set: {
[`fundList.${i}.status`]: 1 // 确认激活
}
});
}
}
mylog.info(`用户${fund.userId} 共更新${acc}`);
job.touch();
});
return typeof done === 'function' && done('矿晶确认完成');
}
const jobs = [
{
name: 'mine',
processor: mine,
type: 'every',
slot: '0 0 3 * * *',
priority: 'highest',
unique: {
id: 'mine'
},
skipImmediate: true,
timezone: "ETC/GMT+8"
},
{
name: 'confirm',
processor: confirm,
type: 'every',
slot: '0 0/10 * * * *', // 59 */1 * * *
priority: 'highest',
unique: {
id: 'confirm'
},
// skipImmediate: true,
timezone: "ETC/GMT+8"
}
];
function mountJobs (Job) {
jobs.map(jobConfig => {
const { name, processor, type, slot, priority, unique, skipImmediate, timezone } = jobConfig;
Job.define(name, {
timezone,
skipImmediate,
priority,
unique: { 'data.type': 'active', 'data.userId': unique.id }
}, processor);
Job[type](slot, name);
});
}
module.exports = Job => mountJobs(Job);