diff --git a/src/jobs/index.js b/src/jobs/index.js index aec2f0a..2e215f9 100644 --- a/src/jobs/index.js +++ b/src/jobs/index.js @@ -10,6 +10,8 @@ module.exports = () => inject(async function startJob(SysConfig) { const jobConn = await mongoose.createConnection(`mongodb://${DB_USER_NAME}:${DB_PASSWD}@${DB_HOST}:${DB_PORT}/${JOB_DB_NAME}`, { useNewUrlParser: true, autoReconnect: true, + useFindAndModify: false, + useUnifiedTopology: true }); mylog.info('连接到任务队列数据库成功'); const Job = new Agenda({ mongo: jobConn }); diff --git a/src/jobs/jobs.js b/src/jobs/jobs.js index 67cc6c6..fa9ac17 100644 --- a/src/jobs/jobs.js +++ b/src/jobs/jobs.js @@ -16,97 +16,107 @@ */ 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: { + + } + }) + 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: 'refreshEstateAndPayBack', - // processor: async (job, done) => { - // //todo: 程序内检查是否可以执行,保证不会启动时错误的自动执行一次 - // const now = new Date().getMinutes(); - // if (now > 0 && now < 58) { - // mylog.error('[Schedule Job] 不在合理时间启动...程序结束'); - // return 0; - // } - // mylog.info('开始定时计算作业...'); - // const query = { startTime: +(new Date().getUTCHours()) + 8 + 1 }; - // const elist = await Estate.find(query).exec(); - // if (!elist || elist.length <= 0) return 0; - // const [ estateSession, userSession, orderSession ] = await Promise.all([ - // mongoose.startSession(), - // mongoose.startSession(), - // mongoose.startSession() - // ]); - // await Promise.all([ - // estateSession.startTransaction(), - // userSession.startTransaction(), - // orderSession.startTransaction() - // ]); - // job.touch(); - // for (let i = 0, length = elist.length; i < length; i++) { - // const estate = elist[i]; - // const estateId = estate.id; - // const userId = estate.currentOwner; - // // todo: 更精确判读是否要回收地产 - // if (!userId) continue; - // const [ user, order ] = await Promise.all([ - // User.findById(userId).exec(), - // EstateOrder.findOne({ - // userId, - // estateId, - // status: 'holding' - // }).exec() - // ]); - // const profit = +estate.price * +estate.profit; - // const payback = profit + estate.price; - // const action = createAction(3, { actor: userId, estate, amount: profit, remain: user.asset }); - // if (!Number.isFinite(payback)) throw new Error('非法的收益数值!'); - // const userOpts = { returnOriginal: false, session: userSession }; - // const orderOpts = { returnOriginal: false, session: orderSession }; - // const estateOpts = { returnOriginal: false, session: estateSession }; - // try { - // await Promise.all([ - // user.increase('profit', payback, userOpts), - // estate.sell(estateOpts), - // order.finish(orderOpts), - // action.save() - // ]); - // await Promise.all([ - // userSession.commitTransaction(), - // orderSession.commitTransaction(), - // estateSession.commitTransaction() - // ]); - // } catch (error) { - // mylog.error(error); - // await Promise.all([ - // action.remove(), - // userSession.abortTransaction(), - // orderSession.abortTransaction(), - // estateSession.abortTransaction() - // ]); - // } finally { - // await Promise.all([ - // userSession.endSession(), - // orderSession.endSession(), - // estateSession.endSession() - // ]); - // } - // job.touch(); - // } - // mylog.info('收益计算分配完成'); - // done(); - // }, - // type: 'every', - // // 写成 '*/59 * * * *' 会出现59分执行一次,下一小时的0分再执行一次 - // // 写成 '*/59 * * * *' 是每59 - // // 最差的解决方案是 在58分执行 - // slot: '59 */1 * * *', // 59th minute per hour - // priority: 'highest', - // unique: { - // id: 'payback001' - // }, - // skipImmediate: true, - // timezone: "ETC/GMT+8" - // } + { + 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 3 * * * *', + priority: 'highest', + unique: { + id: 'mine' + }, + skipImmediate: true, + timezone: "ETC/GMT+8" + } ]; function mountJobs (Job) { jobs.map(jobConfig => {