You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React定时邮件脚本重复执行性能问题及优化方案咨询

解决方案:前端优化 + 服务端重构两种思路

一、前端直接优化:避免定时任务重复创建

你当前的问题核心是定时任务随主组件render重复初始化,而且用隐藏按钮触发的方式非常绕,完全可以通过React生命周期来解决:

1. 重构Timedscripts组件,利用类组件生命周期

把定时任务的创建逻辑移到componentDidMount(仅执行一次),同时在componentWillUnmount里清理任务防止内存泄漏,并且把故障机器的计算逻辑放到定时任务的回调里(确保每次执行都用最新的日志数据):

export default class Timedscripts extends React.Component{
  constructor(props) {
    super(props);
    this.scheduledJob = null; // 保存定时任务引用,方便后续取消
  }

  // 提取计算重复故障机器的逻辑为单独方法
  getRecurringIssueMachines() {
    const { logs } = this.props;
    // 过滤掉测试机器
    const validKioskIDs = logs
      .filter(log => log.KioskID !== 'Testing')
      .map(log => log.KioskID);
    
    // 统计每个机器的故障次数
    const countMap = validKioskIDs.reduce((map, id) => {
      map[id] = (map[id] || 0) + 1;
      return map;
    }, {});

    // 筛选出故障次数≥2的机器
    return Object.keys(countMap).filter(id => countMap[id] >= 2);
  }

  componentDidMount() {
    // 只在组件挂载时创建一次定时任务
    this.scheduledJob = schedule.scheduleJob('0 19 * * *', () => {
      const results = this.getRecurringIssueMachines();
      if (results.length === 0) return;

      const arrayToEmail = results.map(id => `<tr><td>${id}</td></tr>`);
      const to = this.props.msgList.EmailTo;
      const text = `
        <div width="100%" style="text-align:left;">
          <h1 style="text-align:center;">Machines With Reccuring Issues</h1>
          <table border="1" width="100%">
            <tbody style="text-align:left;">
              <tr><td width="300">Machine(s) that have had 2 or more issues within the last 30 days.</td></tr>
              ${arrayToEmail.join('')}
            </tbody>
          </table>
        </div>
      `;
      
      console.log("Sending Email");
      $.get("/send", { to, subject: 'Machines to Watch', text });
    });
  }

  componentWillUnmount() {
    // 组件卸载时取消定时任务,防止内存泄漏
    if (this.scheduledJob) {
      this.scheduledJob.cancel();
    }
  }

  render(){
    // 不需要隐藏按钮了,直接返回空div
    return <div></div>;
  }
}

2. 主组件修改

删掉原来的<script>标签和触发隐藏按钮的逻辑,因为现在Timedscripts会在挂载时自动创建定时任务:

export default class MainComponent extends React.Component{
  // ...其他方法
  render(){
    return(
      <div>
        ...其他HTML
        <TimedScripts 
          logs={this.state.LogHistory} 
          msgList={this.props.msgList}
          // 删掉不需要的props,比如inventoryItems/alerts等,新组件未用到
        />
      </div>
    );
  }
}

二、服务端重构:更可靠的长期方案

前端定时任务的问题在于:用户必须打开页面才能触发,一旦页面关闭就失效。把逻辑移到服务端是更合理的选择,步骤如下:

1. 服务端定时任务(Node.js为例)

用node-schedule或者node-cron创建定时任务,直接从数据库拉取数据(不需要前端传logs):

const schedule = require('node-schedule');
const mysql = require('mysql2/promise'); // 替换为你使用的数据库客户端
const nodemailer = require('nodemailer'); // 直接在服务端发邮件,替代前端的$.get("/send")

// 初始化数据库连接和邮件客户端
const dbConfig = { /* 你的数据库配置:host、user、password、database */ };
const transporter = nodemailer.createTransport({ 
  /* 你的邮件服务配置,比如SMTP:
  host: 'smtp.company.com',
  port: 587,
  secure: false,
  auth: { user: 'alert@company.com', pass: 'your-password' }
  */
});

// 每天19点执行的定时任务
schedule.scheduleJob('0 19 * * *', async () => {
  try {
    const connection = await mysql.createConnection(dbConfig);
    // 调用存储过程获取最近30天的故障日志,过滤测试机器并统计重复故障
    const [rows] = await connection.execute(`
      CALL GetRecurringIssueMachines(30); -- 假设存储过程接收天数参数
    `);
    
    // 处理存储过程返回的数据,筛选出故障次数≥2的机器
    const recurringMachines = rows.filter(row => row.faultCount >= 2).map(row => row.KioskID);
    
    if (recurringMachines.length === 0) {
      console.log("No recurring issue machines to report");
      return;
    }

    // 构造邮件内容
    const arrayToEmail = recurringMachines.map(id => `<tr><td>${id}</td></tr>`);
    const html = `
      <div width="100%" style="text-align:left;">
        <h1 style="text-align:center;">Machines With Reccuring Issues</h1>
        <table border="1" width="100%">
          <tbody style="text-align:left;">
            <tr><td width="300">Machine(s) that have had 2 or more issues within the last 30 days.</td></tr>
            ${arrayToEmail.join('')}
          </tbody>
        </table>
      </div>
    `;

    // 发送邮件
    await transporter.sendMail({
      from: 'your-alert-system@company.com',
      to: 'target-email@company.com', // 可从数据库/配置文件读取收件人
      subject: 'Machines to Watch',
      html: html
    });

    console.log("Alert email sent successfully");
    await connection.end();
  } catch (error) {
    console.error("Error running scheduled job:", error);
  }
});

2. 前端调整

直接删掉Timedscripts组件,不需要前端处理任何定时逻辑,服务端会自动执行任务并发送邮件。

为什么推荐服务端方案?

  • 可靠性更高:不受用户页面是否打开的影响,每天准时执行
  • 性能更好:不需要前端处理大量日志统计,减轻客户端负担
  • 维护更方便:定时规则和邮件逻辑集中在服务端,修改更便捷

内容的提问来源于stack exchange,提问作者Michael

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.06 07:42:39