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"
在我上面的示例中将解决问题。
我有一个人偶脚本,我用它从我使用的报告工具(称为 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"
在我上面的示例中将解决问题。