StartAutoLepao.js 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106
  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, student_num
  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, student_num } = 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. runMode: 'auto'
  63. },
  64. retry: 0
  65. }
  66. if (delayMs > 0) {
  67. try {
  68. await scheduleDelayedRunforgeTask(fireAt, payload, {
  69. name,
  70. account: student_num,
  71. delayMs
  72. })
  73. this.logger.info(
  74. `${name}(${student_num})已写入 Redis 调度(约 ${Math.round(delayMs / 1000)}s 后进 MQ 主队列)`
  75. )
  76. } catch (err) {
  77. this.logger.error(`${name}(${student_num})Redis 调度失败:${err.message || err}`)
  78. }
  79. continue
  80. }
  81. try {
  82. publishRunforgeTask(channel, payload)
  83. this.logger.info(`${name}(${student_num})已投递自动乐跑任务`)
  84. } catch (err) {
  85. this.logger.error(`${name}(${student_num})乐跑投递失败:${err.message || err}`)
  86. }
  87. }
  88. } catch (error) {
  89. this.logger.error(error)
  90. }
  91. }
  92. }
  93. module.exports.StartAutoLepao = StartAutoLepao;