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

watcher.on('add')事件未等待SQL查询完成问题求助

目录监听事件中SQL操作未等待导致重复执行的问题解决

我在实现目录监听功能时遇到一个问题:当添加包含多个子文件夹和文件的目录时,watcher.on('add')事件触发后,在创建首个对应主文件夹的Job(将路径存入数据库)的过程中,日志打印“3”后整个流程就重复执行,没有等待首个Job的SQL创建操作完成。我希望事件能等待SQL查询完成后再继续执行,以下是我的代码:

watcher.on('add', async (filePath) => {
  const relativePath = path.relative(directoryToWatch, filePath);
  const folder = path.dirname(relativePath).split(path.sep)[0];

  console.log(folder);
  console.log("1");

  try {
    let folderExist = folderJobsList.find((item) => item.folder === folder);

    console.log(folderExist);
    console.log("2");

    if (!folderExist) {
      console.log("3");

      // Use a Promise to wait for the job creation
      job = await new Promise(async (resolve, reject) => {
        try {
          const createdJob = await JobModel.create({
            folder,
            status: 'pending',
          });

          console.log("4");
          folderJobsList.push({ folder });
          console.log("5");
          console.log("*********");
          console.log(JSON.stringify(folderJobsList));
          console.log("*********");
          console.log(JSON.stringify(createdJob));
          console.log("---------");

          resolve(createdJob);
        } catch (error) {
          reject(error);
        }
      });

      console.log("6");

      const file = await FileModel.create({
        filename: filePath,
        relativePath: filePath,
        status: 'pending',
        jobId: job.id,
      });

      console.log('File added to the database:', file);

      console.log("7");
    }
  } catch (error) {
    console.error('Error creating File:', error);
  }
})

问题分析

核心问题有两个:

  1. 不必要的Promise嵌套:你用new Promise(async (...))包裹了本身就返回Promise的JobModel.create,这是异步反模式,会破坏Promise链的错误处理逻辑,还可能导致异步流程失控。
  2. 并发事件未串行化:当多个文件/文件夹同时触发add事件时,由于JobModel.create是异步操作,folderJobsList还没来得及更新,后续事件会误以为文件夹不存在,重复执行Job创建流程。

解决方案

下面是修改后的代码,解决了上述问题:

// 新增:用于跟踪正在处理的文件夹,避免并发创建Job
const pendingFolderJobs = {};

watcher.on('add', async (filePath) => {
  const relativePath = path.relative(directoryToWatch, filePath);
  const folder = path.dirname(relativePath).split(path.sep)[0];

  console.log(folder);
  console.log("1");

  try {
    let folderExist = folderJobsList.find(item => item.folder === folder);

    console.log(folderExist);
    console.log("2");

    if (!folderExist) {
      console.log("3");

      // 如果当前文件夹正在处理,等待之前的操作完成
      if (pendingFolderJobs[folder]) {
        await pendingFolderJobs[folder];
        // 重新检查文件夹是否已存在
        folderExist = folderJobsList.find(item => item.folder === folder);
        if (folderExist) {
          // 直接创建文件记录
          const file = await FileModel.create({
            filename: filePath,
            relativePath: filePath,
            status: 'pending',
            jobId: folderExist.jobId
          });
          console.log('File added to the database:', file);
          console.log("7");
          return;
        }
      }

      // 标记当前文件夹正在处理
      const jobPromise = (async () => {
        const createdJob = await JobModel.create({
          folder,
          status: 'pending',
        });

        console.log("4");
        // 存入jobId,后续创建文件需要用到
        folderJobsList.push({ folder, jobId: createdJob.id });
        console.log("5");
        console.log("*********");
        console.log(JSON.stringify(folderJobsList));
        console.log("*********");
        console.log(JSON.stringify(createdJob));
        console.log("---------");

        return createdJob;
      })();

      pendingFolderJobs[folder] = jobPromise;

      try {
        const job = await jobPromise;
        console.log("6");

        const file = await FileModel.create({
          filename: filePath,
          relativePath: filePath,
          status: 'pending',
          jobId: job.id,
        });

        console.log('File added to the database:', file);
        console.log("7");
      } finally {
        // 无论成功失败,都移除处理标记
        delete pendingFolderJobs[folder];
      }
    } else {
      // 文件夹已存在,直接创建文件记录
      const file = await FileModel.create({
        filename: filePath,
        relativePath: filePath,
        status: 'pending',
        jobId: folderExist.jobId
      });
      console.log('File added to the database:', file);
      console.log("7");
    }
  } catch (error) {
    console.error('Error creating File:', error);
    // 出错时清理处理标记,避免后续请求阻塞
    if (pendingFolderJobs[folder]) {
      delete pendingFolderJobs[folder];
    }
  }
});

关键修改点

  • 新增pendingFolderJobs对象:跟踪正在处理的文件夹,同一文件夹的并发事件会等待前一个操作完成,避免重复创建Job。
  • 移除Promise嵌套:直接await JobModel.create返回的Promise,简化代码同时保证异步流程的正确性。
  • 完善folderJobsList存储:存入jobId,后续创建文件时可以直接关联到对应的Job。
  • finally块清理:确保无论操作成功还是失败,都移除处理标记,避免内存泄漏和后续请求阻塞。

内容的提问来源于stack exchange,提问作者Jassem Ben Rayana

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.02 08:00:33