PM2 和 Puppeteer 手表重启

PM2 & Puppeteer Watch Restarting

我有一个人偶脚本,我用它从我使用的报告工具(称为 pivot.js)生成导出:

const fs = require('fs');
const path = require('path');
const events = require('events');
const puppeteer = require('puppeteer');

let eventEmitter = new events.EventEmitter();

const directoryPath = "./storage/"; /* A path to the storage of exported files */

((directoryPath) => {
  fs.mkdir(path.resolve(path.resolve(),
    directoryPath.replace(/^\.*\/|\/?[^\/]+\.[a-z]+|\/$/g, '')), { recursive: true }, error => {
      if (error) console.error(error);
    });
})(directoryPath); /* Creating a storage folder for exported files (if such a folder doesn't exist yet) */

(async () => {

  eventEmitter.once('reportcomplete', () => {

    /*
      All changes should be made within this function.
 
      Available methods:
      - setReport (https://www.flexmonster.com/api/setreport/)
      - exportTo (https://www.flexmonster.com/api/exportto/)
 
      The exportTo method takes two parameters: type and params.
      Callback function will be ignored.
      Possible destination types:
      - plain (the file will be saved by the path defined as a value of the "directoryPath" variable)
      - server (the file will be exported to the server)
 
      Available events (use "eventEmitter" to manage events):
      - ready (https://www.flexmonster.com/api/ready/)
      - reportcomplete (https://www.flexmonster.com/api/reportcomplete/)
      - exportcomplete (https://www.flexmonster.com/api/exportcomplete/)
 
      Additional methods and events can be added using the template.
    */

    eventEmitter.once('reportcomplete', () => { /* Exporting when the report is ready */
      exportTo("csv");
      exportTo("html");
      exportTo("pdf");
      exportTo("image");
      exportTo("excel");
    });

    let exportCount = 0;
    eventEmitter.on('exportcomplete', () => {
      exportCount++;
      if (exportCount == 5) browser.close(); /* Closing the browser when all the exports are complete */
    });

    setReport({
      dataSource: {
        filename: 'https://cdn.flexmonster.com/data/data.json'
      }
    });

  });

  const browser = await puppeteer.launch(); /* Launching the headless browser */
  const page = await browser.newPage(); /* Creating a new page */

  /* A function to set a report for the component dynamically */
  function setReport(report) {
    page.evaluate(report => {
      flexmonster.setReport(report);
    }, report)
  }

  /* This code is responsible for the export itself. It supports five export formats: 
     .html, .xlsx, .pdf, .csv, and .png. */
  function exportTo(type, params) {
    page.evaluate((type, params) => {
      type = type.toLowerCase();
      if (params) {
        if (params.destinationType != "plain" && params.destinationType != "server")
          params.destinationType = "plain";
      }
      else params = { destinationType: "plain" };
      if (!params.filename) params.filename = "pivot";
      flexmonster.exportTo(type, params, (result) => {
        switch (type) {
          case "pdf":
            result.data = result.data.output();
            break;
          case "excel":
            result.data = Array.from(result.data);
            break;
          case "image":
            result.data = result.data.toDataURL();
            break;
        }
        exportHandler(result);
      });
    }, type, params);
  }

  await page.exposeFunction('exportHandler', (result) => {
    switch (result.type) {
      case "excel":
        result.data = Buffer.from(result.data);
        result.type = "xlsx";
        break;
      case "image":
        result.data = Buffer.from(result.data.replace(/^data:image\/\w+;base64,/, ""), 'base64');
        result.type = "png";
        break;
    }
    fs.writeFile(`${directoryPath}${result.filename}.${result.type}`, result.data, 'utf8', error => {
      if (error) console.log(error);
    });
  });


  /* This code adds functions to emit ready, reportcomplete, and exportcomplete events for the browser 
     when called. This approach allows us to handle the component's events in the browser's scope. */
  await page.exposeFunction('onReady', () => {
    eventEmitter.emit('ready')
  });
  await page.exposeFunction('onReportComplete', () => {
    eventEmitter.emit('reportcomplete')
  });
  await page.exposeFunction('onExportComplete', () => {
    eventEmitter.emit('exportcomplete')
  });

  /*  Reading the file with the component and setting it as the browser page's contents */
  await page.setContent(fs.readFileSync('index.html', 'utf8'));

  /* This code runs in the page's scope, subscribing the browser window to the component's ready, 
     reportcomplete, and exportcomplete events */
  await page.evaluate(() => {
    window.addEventListener('ready', () => window.onReady());
    window.addEventListener('reportcomplete', () => window.onReportComplete());
    window.addEventListener('exportcomplete', () => window.onExportComplete());
  });

})();

然后我使用 PM2 来查看文件,允许我换出用于生成不同报告的代码,使用:

pm2 start pivot.js --watch

我遇到的问题是,每当我删除存储文件夹(脚本写入其中)的内容时,都会立即出现一个新的导出。几乎就像脚本在不断被调用,或者 PM2 正在重新启动。

PM2 的两个日志都是空白的。但是在 运行:

之后

pm2 show 0

我收到以下信息:

│ status            │ stopping                                            │
│ name              │ pivot                                               │
│ namespace         │ default                                             │
│ version           │ 1.0.0                                               │
│ restarts          │ 1957                                                │
│ uptime            │ 0                                                   │
│ script path       │ C:\Users\admin\Documents\Windows Puppeteer\pivot.js │
│ script args       │ N/A                                                 │
│ error log path    │ C:\Users\admin\.pm2\logs\pivot-error.log            │
│ out log path      │ C:\Users\admin\.pm2\logs\pivot-out.log              │
│ pid path          │ C:\Users\admin\.pm2\pids\pivot-0.pid                │
│ interpreter       │ node                                                │
│ interpreter args  │ N/A                                                 │
│ script id         │ 0                                                   │
│ exec cwd          │ C:\Users\admin\Documents\Windows Puppeteer          │
│ exec mode         │ fork_mode                                           │
│ node.js version   │ 14.15.1                                             │
│ node env          │ N/A                                                 │
│ watch & reload    │ ✔                                                   │
│ unstable restarts │ 0                                                   │
│ created at        │ 2020-11-30T01:24:27.461Z                            │

希望能帮到你。

问题是人偶脚本(名为 pivot.js)将返回的文件转储到名为“storage”的文件夹中。存储在与 pivot.js 相同的目录中,这意味着当 PM2 监视该目录时,它正在创建一个无限循环。解决方案是使用忽略监视选项。

正在这样创建生态系统文件:

module.exports = {
  apps : [{
    script: 'pivot.js',
    watch: '.',
    ignore_watch : ["node_modules", "storage"]
  }],
  ...
};

或使用:

pm2 start pivot.js --watch --ignore-watch="storage"

在我上面的示例中将解决问题。