Skip to content

Commit

Permalink
fix: 使用pid的方式修复file read timeout问题 (#410)
Browse files Browse the repository at this point in the history
* feat: 根据pid判断某个进程是否存在

--story=20220716

* feat: 使用fileExit函数确保heart-beat-pid.json存在

--story=20220716

* feat: 在readtimeout时删除心跳和更新进程lock文件

--story=20220718

* feat: 在readtimeout时删除心跳和更新进程lock文件后继续执行后续逻辑启动心跳进程

--story=20220718

* feat: 当read timeout时删除lock文件

--story=20220718

* feat: 使用heart-beat.pid代替heart-beat-pid.json

--story=20220718

* feat: 去掉pm2日志

--story=20220720

* feat: 增加去掉PM2日志注释,使用filePath代替file

--story=20220720

Co-authored-by: guichezhang <[email protected]>
  • Loading branch information
happyCoding1024 and guichezhang authored Jul 20, 2022
1 parent e03bb0e commit c587eef
Show file tree
Hide file tree
Showing 9 changed files with 88 additions and 13 deletions.
27 changes: 27 additions & 0 deletions packages/feflow-cli/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions packages/feflow-cli/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@
"@types/minimist": "^1.2.0",
"@types/nedb": "^1.8.10",
"@types/osenv": "^0.1.0",
"@types/ps-node": "^0.1.1",
"@types/request-promise": "^4.1.45",
"@types/semver": "^6.0.1",
"@types/yeoman-environment": "^2.10.1"
Expand Down Expand Up @@ -80,6 +81,7 @@
"osenv": "^0.1.5",
"package-json": "^6.5.0",
"pm2": "^5.2.0",
"ps-node": "^0.1.6",
"request": "^2.88.0",
"request-promise": "^4.2.6",
"semver": "^7.3.2",
Expand Down
18 changes: 13 additions & 5 deletions packages/feflow-cli/src/core/resident/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,13 @@ import {
UPDATE_KEY,
UPDATE_LOCK,
FEFLOW_HOME,
FEFLOW_UPDATE_BEAT_PROCESS,
HEART_BEAT_PID,
} from '../../shared/constant';
import { isProcessExist } from '../../shared/process';
import { checkProcessExistByPid } from '../../shared/process';
import { safeDump } from '../../shared/yaml';
import { readFileSync } from '../../shared/file';
import { createPm2Process, ErrProcCallback } from './pm2';
import { isFileExist } from '../../shared/fs';

const updateBeatScriptPath = path.join(__dirname, './update-beat.js');
const updateScriptPath = path.join(__dirname, './update');
Expand Down Expand Up @@ -52,8 +54,9 @@ function startUpdateBeat(ctx: Feflow) {
debug: ctx.args.debug,
silent: ctx.args.silent,
},
error_file: `${FEFLOW_HOME}/.pm2/logs/feflow-update-beat-process-error.log`,
out_file: `${FEFLOW_HOME}/.pm2/logs/feflow-update-beat-process-out.log`,
// 由于心跳进程会不断写日志导致pm2日志文件过大,而且对于用户来说并关心心跳进程的日志,对于开发同学可以通过pm2 log来查看心跳进程的日志
error_file: '/dev/null',
out_file: '/dev/null',
pid_file: `${FEFLOW_HOME}/.pm2/pid/app-pm_id.pid`,
};

Expand Down Expand Up @@ -183,8 +186,13 @@ async function checkLock(updateData: UpdateData) {
async function ensureFilesUnlocked(ctx: Feflow) {
const beatLockPath = path.join(FEFLOW_HOME, BEAT_LOCK);
const updateLockPath = path.join(FEFLOW_HOME, UPDATE_LOCK);
const heartBeatPidPath = path.join(FEFLOW_HOME, HEART_BEAT_PID);
try {
const isPsExist = await isProcessExist(FEFLOW_UPDATE_BEAT_PROCESS);
if (!isFileExist(heartBeatPidPath)) return;
// 当heart-beat-pid.json存在时,说明启动了最新的心跳进程,文件中会被写入当前的心跳进程,此时根据pid判断进程是否存在
const heartBeatPid = readFileSync(heartBeatPidPath);
ctx.logger.debug('heartBeatPid:', heartBeatPid);
const isPsExist = await checkProcessExistByPid(heartBeatPid);
ctx.logger.debug('fefelow-update-beat-process is exist:', isPsExist);
if (lockFile.checkSync(beatLockPath) && !isPsExist) {
ctx.logger.debug('beat file unlock');
Expand Down
8 changes: 8 additions & 0 deletions packages/feflow-cli/src/core/resident/update-beat.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,15 @@ import {
BEAT_LOCK,
UPDATE_KEY,
UPDATE_LOCK,
FEFLOW_HOME,
HEART_BEAT_PID,
} from '../../shared/constant';
import createLogger from '../logger';
import { getInstalledPlugins, getLatestVersion, getUniversalPluginVersion } from './utils';
import { getPkgInfo } from '../native/install';
import Feflow from '../index';
import { isValidConfig } from '../../shared/type-predicates';
import { fileExit, writeFileSync } from '../../shared/file';
import pkgJson from '../../../package.json';

interface ErrorInstance {
Expand Down Expand Up @@ -179,6 +182,11 @@ const queryUniversalPluginsUpdate = async () => {
}
};

// 记录心跳进程的pid
const heartBeatPidPath = path.join(FEFLOW_HOME, HEART_BEAT_PID);
fileExit(heartBeatPidPath);
writeFileSync(heartBeatPidPath, `${process.pid}`);

// startBeat
setInterval(heartBeat, BEAT_GAP);

Expand Down
2 changes: 2 additions & 0 deletions packages/feflow-cli/src/shared/constant.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,8 @@ export const CACHE_FILE = '.feflowCache.yml';

export const HEART_BEAT_COLLECTION = 'heart-beat.json';

export const HEART_BEAT_PID = 'heart-beat.pid';

export const HEART_BEAT_COLLECTION_LOG = 'heart_beat-log.db';

export const UPDATE_COLLECTION = 'update.json';
Expand Down
17 changes: 11 additions & 6 deletions packages/feflow-cli/src/shared/file.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,9 @@ export function fileExit(filePath: string) {
}
}
// 文件中读取json对象的某个value
export const getKeyFormFile = (file: string, key: string) => {
export const getKeyFormFile = (filePath: string, key: string) => {
try {
const jsonString = fs.readFileSync(file, 'utf-8');
const jsonString = fs.readFileSync(filePath, 'utf-8');
if (jsonString) {
const jsonData = JSON.parse(jsonString);
return jsonData[key];
Expand All @@ -29,9 +29,9 @@ export const getKeyFormFile = (file: string, key: string) => {
}
};
// 文件中写入一个json字符串
export const setKeyToFile = (file: string, key: string, value: any): any => {
export const setKeyToFile = (filePath: string, key: string, value: any): any => {
try {
const jsonString = fs.readFileSync(file, 'utf-8');
const jsonString = fs.readFileSync(filePath, 'utf-8');
let jsonData;
if (jsonString) {
jsonData = JSON.parse(jsonString);
Expand All @@ -41,12 +41,17 @@ export const setKeyToFile = (file: string, key: string, value: any): any => {
[key]: value,
};
}
fs.writeFileSync(file, JSON.stringify(jsonData, null, 4), 'utf-8');
fs.writeFileSync(filePath, JSON.stringify(jsonData, null, 4), 'utf-8');
} catch (e) {
console.log('setKeyToCache error =>', e);
}
};

// 同步读取文件
export const readFileSync = (filePath: string) => fs.readFileSync(filePath, 'utf8').replace(/^\ufeff/u, '');
// 同步写入文件
export const writeFileSync = (filePath: string, data: string) => {
fs.writeFileSync(filePath, data);
};
export class Config {
static loadConfigFile(filePath: string) {
switch (path.extname(filePath)) {
Expand Down
4 changes: 4 additions & 0 deletions packages/feflow-cli/src/shared/fs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,3 +43,7 @@ async function copyFiles(srcPath: string, tarPath: string, files: string[]) {
}
}));
}

export function isFileExist(filePath: string) {
return fs.existsSync(filePath);
}
5 changes: 3 additions & 2 deletions packages/feflow-cli/src/shared/lock-file.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import fs from 'fs';
import lockFile from 'lockfile';
import { Logger } from '../core/logger';

export default class LockFile {
private readonly filePath: string;
private readonly lockKey: string;
Expand Down Expand Up @@ -136,7 +135,9 @@ export default class LockFile {
// another writing is running
if (this.tryCount >= this.tryMax) {
this.tryCount = 0;
return this.logger.error(`file read time out ${this.filePath}`);
// 解锁文件
this.unlock();
cb();
}
this.tryCount += 1;
setTimeout(() => {
Expand Down
18 changes: 18 additions & 0 deletions packages/feflow-cli/src/shared/process.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// 查询进程的代码参考https://github.com/neekey/ps
import { spawn } from 'child_process';
import os from 'os';
import psNode from 'ps-node';

/**
* End of line.
Expand Down Expand Up @@ -85,3 +86,20 @@ export async function isProcessExist(psName: string) {
console.error(e);
}
};

// 根据进程id判断某个进程是否存在
export async function checkProcessExistByPid(pid: number | string): Promise<boolean> {
return new Promise((resolve, reject) => {
if (!pid) return resolve(false);

psNode.lookup({ pid }, (err, psList) => {
if (err) return reject(err);

if (Array.isArray(psList) && psList[0]) {
resolve(true);
} else {
resolve(false);
}
});
});
}

0 comments on commit c587eef

Please sign in to comment.