Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: 使用pid的方式修复file read timeout问题 #410

Merged
merged 8 commits into from
Jul 20, 2022
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);
}
});
});
}