'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.2; // 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 fundlist = fund.fundList; for (let i = 0, len = fundlist.length; i < len; ++i) { const fund = fundlist[i]; const released = fund.releasedAmout || 0; if (released === fund.releasedAmout) { await Fund.findByIdAndUpdate(fund.id, { $set: { [`fundList.${i}.status`]: 2 //标记失效 } }); continue; } const allInviteReward = (+user.group.length || 0) * 10; // 计算出从开始到现在邀请奖励总额 const rewardInvite = allInviteReward - (fund.option.usedGroupReward || 0); // 求增量: 总额 - 已领取总额(fundSum) // 挖矿奖励 = 充值金额奖励 + 社区奖励 const rewardMine = +fund.amount * tokenReleaseRate; const reward = rewardMine + rewardInvite; await Fund.findByIdAndUpdate(fund.id, { $inc: { 'asset.vic': reward, }, $set: { 'option.usedGroupReward': rewardInvite, // 本次的奖励值累加到已领取团队奖励总和内 'asset.usdt': allInviteReward // 用来记录所有社群奖励总额 } }).then(() => { createAction(1, { userId: fund.userId, tokenType: 'vic', amount: rewardMine, remain: fund.asset }).save(); rewardInvite > 0 && createAction(2, { userId: fund.userId, tokenType: 'vic', amount: rewardInvite, remain: fund.asset }).save(); }); } }; const jobs = [ { name: 'mine', processor: async (job, done) => { //todo: 程序内检查是否可以执行,保证不会启动时错误的自动执行一次 const now = new Date(); if (now.getHours() !== 23 && now.getMinutes() < 58) { mylog.error('[Schedule Job] 不在合理时间启动...程序结束'); return 0; } mylog.info('[Schedule Job] 开始定时计算作业...'); let currentIndex = await system.findOne({ key: 'userIndex4job' }).exec(); if (typeof currentIndex !== 'number') { currentIndex = 0; await new system({ key: currentIndex }).save(); } // 批量更新,每次十个 const userFundList = await Fund.find().sort('_id').limit(10).skip(currentIndex); job.touch(); if (!userFundList || !Array.isArray(userFundList)) return 0; currentIndex += userFundList.length; for (let i = 0, len = userFundList.length; i < len; ++i) { const fundItem = userFundList[i]; // 一条数据库fund表记录 const funds = fundItem.fundList; if (!funds || !Array.isArray(funds)) continue; const user = await User.findOne({ id: fundItem.userId }).exec(); doReward(user, funds); job.touch(); } mylog.info('收益计算分配完成'); done(); }, type: 'every', slot: '0 0 3 * * ? *', priority: 'highest', unique: { id: 'mine' }, 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);