Merge dev: Add automatic port finder
Some checks failed
CI/CD / lint-and-build (push) Has been cancelled
Some checks failed
CI/CD / lint-and-build (push) Has been cancelled
This commit is contained in:
commit
382b584740
77
backend/lib/portFinder.js
Normal file
77
backend/lib/portFinder.js
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
// Утилита для поиска свободного порта
|
||||||
|
|
||||||
|
const net = require('net');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Проверяет, свободен ли порт
|
||||||
|
* @param {number} port - Порт для проверки
|
||||||
|
* @returns {Promise<boolean>} - true если порт свободен, false если занят
|
||||||
|
*/
|
||||||
|
function isPortAvailable(port) {
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
const server = net.createServer();
|
||||||
|
|
||||||
|
server.listen(port, () => {
|
||||||
|
server.once('close', () => {
|
||||||
|
resolve(true);
|
||||||
|
});
|
||||||
|
server.close();
|
||||||
|
});
|
||||||
|
|
||||||
|
server.on('error', (err) => {
|
||||||
|
if (err.code === 'EADDRINUSE') {
|
||||||
|
resolve(false);
|
||||||
|
} else {
|
||||||
|
resolve(false);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Находит свободный порт начиная с заданного
|
||||||
|
* @param {number} startPort - Начальный порт для поиска
|
||||||
|
* @param {number} maxAttempts - Максимальное количество попыток (по умолчанию 10)
|
||||||
|
* @returns {Promise<number>} - Свободный порт
|
||||||
|
*/
|
||||||
|
async function findFreePort(startPort, maxAttempts = 10) {
|
||||||
|
for (let i = 0; i < maxAttempts; i++) {
|
||||||
|
const port = startPort + i;
|
||||||
|
const available = await isPortAvailable(port);
|
||||||
|
if (available) {
|
||||||
|
return port;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw new Error(
|
||||||
|
`Не удалось найти свободный порт в диапазоне ${startPort}-${startPort + maxAttempts - 1}`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Получить порт для сервера (проверяет занятость и находит свободный)
|
||||||
|
* @param {number} defaultPort - Порт по умолчанию
|
||||||
|
* @param {boolean} autoFind - Автоматически искать свободный если занят
|
||||||
|
* @returns {Promise<number>} - Порт для использования
|
||||||
|
*/
|
||||||
|
async function getServerPort(defaultPort, autoFind = true) {
|
||||||
|
const available = await isPortAvailable(defaultPort);
|
||||||
|
if (available) {
|
||||||
|
return defaultPort;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!autoFind) {
|
||||||
|
throw new Error(`Порт ${defaultPort} занят`);
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(`⚠️ Порт ${defaultPort} занят, ищем свободный...`);
|
||||||
|
const freePort = await findFreePort(defaultPort + 1);
|
||||||
|
console.log(`✅ Найден свободный порт: ${freePort}`);
|
||||||
|
return freePort;
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
isPortAvailable,
|
||||||
|
findFreePort,
|
||||||
|
getServerPort,
|
||||||
|
};
|
||||||
|
|
||||||
@ -9,7 +9,11 @@ const errorHandler = require('./middleware/errorHandler');
|
|||||||
const { generalLimiter } = require('./middleware/rateLimiter');
|
const { generalLimiter } = require('./middleware/rateLimiter');
|
||||||
|
|
||||||
const app = express();
|
const app = express();
|
||||||
const PORT = process.env.PORT || 3001;
|
const { getServerPort } = require('./lib/portFinder');
|
||||||
|
|
||||||
|
// Получаем порт (с автоматическим поиском свободного если нужно)
|
||||||
|
const DEFAULT_PORT = process.env.PORT || 3001;
|
||||||
|
let PORT = DEFAULT_PORT;
|
||||||
|
|
||||||
// Middleware
|
// Middleware
|
||||||
app.use(simpleLogger); // Простое логирование запросов
|
app.use(simpleLogger); // Простое логирование запросов
|
||||||
@ -63,10 +67,23 @@ app.use((req, res) => {
|
|||||||
// Обработка ошибок (должен быть последним middleware)
|
// Обработка ошибок (должен быть последним middleware)
|
||||||
app.use(errorHandler);
|
app.use(errorHandler);
|
||||||
|
|
||||||
// Запуск сервера
|
// Запуск сервера с автоматическим поиском свободного порта
|
||||||
app.listen(PORT, () => {
|
(async () => {
|
||||||
winstonLogger.info(`🚀 Server is running on http://localhost:${PORT}`);
|
try {
|
||||||
winstonLogger.info(`📡 Health check: http://localhost:${PORT}/api/health`);
|
PORT = await getServerPort(DEFAULT_PORT, true);
|
||||||
winstonLogger.info(`📝 Environment: ${process.env.NODE_ENV || 'development'}`);
|
app.listen(PORT, () => {
|
||||||
});
|
winstonLogger.info(`🚀 Server is running on http://localhost:${PORT}`);
|
||||||
|
winstonLogger.info(`📡 Health check: http://localhost:${PORT}/api/health`);
|
||||||
|
winstonLogger.info(`📝 Environment: ${process.env.NODE_ENV || 'development'}`);
|
||||||
|
if (PORT !== DEFAULT_PORT) {
|
||||||
|
winstonLogger.info(
|
||||||
|
`ℹ️ Используется порт ${PORT} вместо ${DEFAULT_PORT} (занят)`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
winstonLogger.error(`❌ Ошибка запуска сервера: ${error.message}`);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
|
||||||
|
|||||||
@ -3,7 +3,7 @@
|
|||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "next dev --turbopack",
|
"dev": "node scripts/devWithPort.js",
|
||||||
"build": "next build",
|
"build": "next build",
|
||||||
"start": "next start",
|
"start": "next start",
|
||||||
"lint": "next lint",
|
"lint": "next lint",
|
||||||
|
|||||||
42
frontend/scripts/devWithPort.js
Normal file
42
frontend/scripts/devWithPort.js
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
// Скрипт для запуска Next.js dev с автоматическим поиском свободного порта
|
||||||
|
|
||||||
|
const { spawn } = require('child_process');
|
||||||
|
const { findFreePort } = require('./findPort');
|
||||||
|
|
||||||
|
const DEFAULT_PORT = 3000;
|
||||||
|
|
||||||
|
(async () => {
|
||||||
|
try {
|
||||||
|
const port = await findFreePort(DEFAULT_PORT);
|
||||||
|
|
||||||
|
if (port !== DEFAULT_PORT) {
|
||||||
|
console.log(`⚠️ Порт ${DEFAULT_PORT} занят, используем порт ${port}`);
|
||||||
|
} else {
|
||||||
|
console.log(`✅ Порт ${port} свободен`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Запускаем Next.js dev с найденным портом
|
||||||
|
const nextDev = spawn('npx', ['next', 'dev', '--turbopack', '-p', String(port)], {
|
||||||
|
stdio: 'inherit',
|
||||||
|
shell: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
nextDev.on('error', (error) => {
|
||||||
|
console.error('Ошибка запуска Next.js:', error);
|
||||||
|
process.exit(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
nextDev.on('exit', (code) => {
|
||||||
|
process.exit(code || 0);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Обработка Ctrl+C
|
||||||
|
process.on('SIGINT', () => {
|
||||||
|
nextDev.kill('SIGINT');
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Ошибка поиска порта:', error.message);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
|
||||||
56
frontend/scripts/findPort.js
Normal file
56
frontend/scripts/findPort.js
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
// Скрипт для поиска свободного порта для Next.js
|
||||||
|
|
||||||
|
const net = require('net');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Проверяет, свободен ли порт
|
||||||
|
*/
|
||||||
|
function isPortAvailable(port) {
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
const server = net.createServer();
|
||||||
|
|
||||||
|
server.listen(port, () => {
|
||||||
|
server.once('close', () => {
|
||||||
|
resolve(true);
|
||||||
|
});
|
||||||
|
server.close();
|
||||||
|
});
|
||||||
|
|
||||||
|
server.on('error', () => {
|
||||||
|
resolve(false);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Находит свободный порт начиная с заданного
|
||||||
|
*/
|
||||||
|
async function findFreePort(startPort, maxAttempts = 10) {
|
||||||
|
for (let i = 0; i < maxAttempts; i++) {
|
||||||
|
const port = startPort + i;
|
||||||
|
const available = await isPortAvailable(port);
|
||||||
|
if (available) {
|
||||||
|
return port;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw new Error(
|
||||||
|
`Не удалось найти свободный порт в диапазоне ${startPort}-${startPort + maxAttempts - 1}`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Если запущен как скрипт
|
||||||
|
if (require.main === module) {
|
||||||
|
const startPort = parseInt(process.argv[2]) || 3000;
|
||||||
|
findFreePort(startPort)
|
||||||
|
.then((port) => {
|
||||||
|
console.log(port);
|
||||||
|
process.exit(0);
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
console.error(error.message);
|
||||||
|
process.exit(1);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = { isPortAvailable, findFreePort };
|
||||||
|
|
||||||
Loading…
Reference in New Issue
Block a user