StartAutoLepao.js 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105
  1. const API = require("../../lib/API");
  2. const db = require('../../plugin/DataBase/db')
  3. const Redis = require('../../plugin/DataBase/Redis')
  4. const mq = require('../../plugin/mq')
  5. const { assertRunforgeTaskIngress, publishRunforgeTask } = require('../../plugin/mq/runforgeTaskMq')
  6. const { scheduleDelayedRunforgeTask } = require('../../plugin/mq/lepaoAutoScheduleRedis')
  7. const { BaseStdResponse } = require("../../BaseStdResponse");
  8. class StartAutoLepao extends API {
  9. constructor() {
  10. super();
  11. this.noEncrypt()
  12. this.setPath('/Corn/StartAutoLepao');
  13. this.setMethod('GET');
  14. }
  15. async onRequest(req, res) {
  16. try {
  17. res.json({
  18. ...BaseStdResponse.OK
  19. })
  20. const day = new Date().getDay()
  21. const hour = new Date().getHours()
  22. this.logger.info('开始执行自动乐跑任务')
  23. let sql = `
  24. SELECT name, create_user, student_num, token, uid, school_id, state
  25. FROM lepao_account
  26. WHERE auto_run = 1
  27. AND (auto_time = ? OR (auto_time = -1 AND today_auto_time = ?))
  28. AND JSON_CONTAINS(auto_day, CAST(? AS JSON))
  29. `
  30. let r = await db.query(sql, [hour, hour, day])
  31. if (!r)
  32. return this.logger.error('获取自动乐跑账号失败!')
  33. // 为本小时内随机打散投递时间,减轻瞬时并发(0 ~ 当前小时剩余毫秒数)
  34. const nowMs = Date.now()
  35. const hourEnd = new Date()
  36. hourEnd.setHours(hourEnd.getHours() + 1, 0, 0, 0)
  37. const spreadWindowMs = Math.max(0, hourEnd.getTime() - nowMs)
  38. let channel
  39. try {
  40. channel = await mq.getChannel('lepao_corn')
  41. await assertRunforgeTaskIngress(channel, this.logger)
  42. } catch (err) {
  43. this.logger.error(`自动乐跑:连接 MQ 或声明拓扑失败:${err.message || err}`)
  44. return
  45. }
  46. for (const item of r) {
  47. const { name, create_user, student_num, token, uid, school_id, state } = item
  48. const isSuccess = await Redis.get(`lepaoSuccess:${student_num}`)
  49. if (isSuccess) {
  50. this.logger.info(`${name}(${student_num})当天已乐跑成功,不执行自动乐跑`)
  51. continue
  52. }
  53. const delayMs = spreadWindowMs > 0 ? Math.floor(Math.random() * spreadWindowMs) : 0
  54. const fireAt = nowMs + delayMs
  55. const taskId = `lepao:auto:${fireAt}:${student_num}`
  56. const payload = {
  57. id: taskId,
  58. type: 'lepao.startRun',
  59. data: {
  60. taskId,
  61. account: student_num
  62. },
  63. retry: 0
  64. }
  65. if (delayMs > 0) {
  66. try {
  67. await scheduleDelayedRunforgeTask(fireAt, payload, {
  68. name,
  69. account: student_num,
  70. delayMs
  71. })
  72. this.logger.info(
  73. `${name}(${student_num})已写入 Redis 调度(约 ${Math.round(delayMs / 1000)}s 后进 MQ 主队列)`
  74. )
  75. } catch (err) {
  76. this.logger.error(`${name}(${student_num})Redis 调度失败:${err.message || err}`)
  77. }
  78. continue
  79. }
  80. try {
  81. publishRunforgeTask(channel, payload)
  82. this.logger.info(`${name}(${student_num})已投递自动乐跑任务`)
  83. } catch (err) {
  84. this.logger.error(`${name}(${student_num})乐跑投递失败:${err.message || err}`)
  85. }
  86. }
  87. } catch (error) {
  88. this.logger.error(error)
  89. }
  90. }
  91. }
  92. module.exports.StartAutoLepao = StartAutoLepao;