You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

236 lines
7.1 KiB

#!/usr/bin/env node
const { execSync, exec } = require('child_process');
const fs = require('fs');
const path = require('path');
// 检查端口是否被占用
function isPortTaken(port) {
return new Promise((resolve) => {
// 在Linux上使用lsof检查端口占用
try {
execSync(`lsof -i :${port}`, { stdio: 'ignore' });
resolve(true);
} catch (error) {
resolve(false);
}
});
}
// 查找占用端口的进程ID
function findProcessUsingPort(port) {
try {
const output = execSync(`lsof -i :${port} | grep LISTEN`, { encoding: 'utf8' });
const lines = output.trim().split('\n');
if (lines.length > 0) {
const parts = lines[0].trim().split(/\s+/);
return { pid: parts[1], process: parts[0], user: parts[2] };
}
} catch (error) {
console.log(`未找到占用端口 ${port} 的进程`);
}
return null;
}
// 停止指定进程
function stopProcess(pid) {
try {
execSync(`kill -9 ${pid}`);
console.log(`成功停止进程 ${pid}`);
return true;
} catch (error) {
console.error(`停止进程 ${pid} 失败:`, error.message);
return false;
}
}
// 修改PM2配置文件中的端口
function updatePM2ConfigFile(newPort) {
const configPath = path.join(__dirname, 'ecosystem.config.js');
try {
let content = fs.readFileSync(configPath, 'utf8');
// 备份配置文件
const backupPath = configPath + '.bak.' + Date.now();
fs.writeFileSync(backupPath, content);
console.log(`已创建配置备份: ${backupPath}`);
// 修改production环境端口
content = content.replace(/PORT:\s*3001/g, `PORT: ${newPort}`);
fs.writeFileSync(configPath, content);
console.log(`已将PM2配置中的端口修改为: ${newPort}`);
return true;
} catch (error) {
console.error('修改PM2配置文件失败:', error.message);
return false;
}
}
// 重启PM2应用
function restartPM2App() {
try {
execSync('pm2 restart ecosystem.config.js', { stdio: 'inherit' });
return true;
} catch (error) {
console.error('重启PM2应用失败:', error.message);
return false;
}
}
// 主函数
async function main() {
console.log('=== 微信小程序后端服务 - 端口冲突修复工具 ===\n');
const originalPort = 3001;
let newPort = 3001;
// 检查原始端口是否被占用
const isOriginalPortTaken = await isPortTaken(originalPort);
if (isOriginalPortTaken) {
console.log(`发现端口 ${originalPort} 被占用!`);
// 查找占用进程
const processInfo = findProcessUsingPort(originalPort);
if (processInfo) {
console.log(`占用端口的进程信息:`);
console.log(`- 进程ID: ${processInfo.pid}`);
console.log(`- 进程名称: ${processInfo.process}`);
console.log(`- 用户: ${processInfo.user}`);
// 询问是否停止该进程
const readline = require('readline').createInterface({
input: process.stdin,
output: process.stdout
});
readline.question(`是否停止该进程以释放端口 ${originalPort}? (y/n): `, (answer) => {
readline.close();
if (answer.toLowerCase() === 'y') {
if (stopProcess(processInfo.pid)) {
console.log(`端口 ${originalPort} 已被释放,正在重启应用...`);
restartPM2App();
}
} else {
// 查找可用端口
console.log('正在查找可用端口...');
let foundPort = false;
for (let i = 3002; i <= 3100; i++) {
execSync(`lsof -i :${i}`, { stdio: 'ignore' }, (error) => {
if (error) {
newPort = i;
foundPort = true;
// 修改PM2配置并重启
if (updatePM2ConfigFile(newPort)) {
console.log(`已切换到可用端口: ${newPort}`);
console.log('正在重启PM2应用...');
restartPM2App();
}
}
});
if (foundPort) break;
}
if (!foundPort) {
console.error('未找到可用端口,请手动指定一个未被占用的端口。');
}
}
});
} else {
console.error('无法确定占用端口的进程,请手动检查端口占用情况。');
}
} else {
console.log(`端口 ${originalPort} 未被占用,检查应用状态...`);
// 检查PM2应用状态
try {
const statusOutput = execSync('pm2 status wechat-app', { encoding: 'utf8' });
console.log(statusOutput);
// 提示用户重启应用
const readline = require('readline').createInterface({
input: process.stdin,
output: process.stdout
});
readline.question('是否需要重启应用? (y/n): ', (answer) => {
readline.close();
if (answer.toLowerCase() === 'y') {
restartPM2App();
} else {
console.log('操作已取消。');
}
});
} catch (error) {
console.error('检查PM2应用状态失败:', error.message);
console.log('建议尝试手动重启应用: pm2 restart wechat-app');
}
}
}
// 提供非交互式修复选项
function provideNonInteractiveFix() {
console.log('\n=== 非交互式修复选项 ===');
console.log('1. 强制释放3001端口并重启应用');
console.log('2. 使用备用端口3004并更新配置');
console.log('3. 查看当前端口占用情况');
const readline = require('readline').createInterface({
input: process.stdin,
output: process.stdout
});
readline.question('请选择修复方式 (1-3): ', (answer) => {
readline.close();
switch (answer) {
case '1':
const processInfo = findProcessUsingPort(3001);
if (processInfo && stopProcess(processInfo.pid)) {
console.log('正在重启应用...');
restartPM2App();
} else {
console.log('端口未被占用或无法停止占用进程');
}
break;
case '2':
if (updatePM2ConfigFile(3003)) {
console.log('正在重启应用...');
restartPM2App();
}
break;
case '3':
try {
console.log('端口占用情况:');
execSync('netstat -tuln | grep 300', { stdio: 'inherit' });
} catch (error) {
console.log('未找到相关端口占用信息');
}
break;
default:
console.log('无效选项,操作已取消。');
}
});
}
// 运行主程序
main().catch(err => {
console.error('修复过程中发生错误:', err);
provideNonInteractiveFix();
});
// 提供帮助信息
setTimeout(() => {
console.log('\n如果自动修复失败,可以尝试以下手动解决方案:');
console.log('1. 检查端口占用: lsof -i :3001 或 netstat -ano | findstr :3001');
console.log('2. 停止占用进程: kill -9 [进程ID]');
console.log('3. 或者修改PM2配置使用其他端口:');
console.log(' - 编辑 ecosystem.config.js 文件');
console.log(' - 将 PORT: 3001 修改为其他可用端口');
console.log(' - 保存并运行: pm2 restart ecosystem.config.js');
}, 1000);