Remove deprecated Nginx configuration for stream.graff.estate and update package dependencies in session-server and client

- Deleted the Nginx configuration file for stream.graff.estate.
- Updated bun.lock files in both client and session-server to include new dependencies and version updates.
- Added 'tree-kill' dependency to session-server for improved process management.
- Refactored process termination logic in session-server to utilize 'tree-kill' for reliable process termination.
This commit is contained in:
2026-02-20 12:46:15 +05:00
parent 2a58a47077
commit 0243284da0
6 changed files with 68 additions and 139 deletions
+5 -1
View File
@@ -1,5 +1,6 @@
{
"lockfileVersion": 1,
"configVersion": 0,
"workspaces": {
"": {
"name": "client",
@@ -27,6 +28,7 @@
"@types/uuid": "^11.0.0",
"@vitejs/plugin-react-swc": "^4.1.0",
"autoprefixer": "^10.4.21",
"baseline-browser-mapping": "^2.9.2",
"eslint": "^9.36.0",
"eslint-plugin-react-hooks": "^5.2.0",
"eslint-plugin-react-refresh": "^0.4.22",
@@ -282,7 +284,7 @@
"balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="],
"baseline-browser-mapping": ["baseline-browser-mapping@2.8.10", "", { "bin": { "baseline-browser-mapping": "dist/cli.js" } }, "sha512-uLfgBi+7IBNay8ECBO2mVMGZAc1VgZWEChxm4lv+TobGdG82LnXMjuNGo/BSSZZL4UmkWhxEHP2f5ziLNwGWMA=="],
"baseline-browser-mapping": ["baseline-browser-mapping@2.9.7", "", { "bin": { "baseline-browser-mapping": "dist/cli.js" } }, "sha512-k9xFKplee6KIio3IDbwj+uaCLpqzOwakOgmqzPezM0sFJlFKcg30vk2wOiAJtkTSfx0SSQDSe8q+mWA/fSH5Zg=="],
"binary-extensions": ["binary-extensions@2.3.0", "", {}, "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw=="],
@@ -666,6 +668,8 @@
"anymatch/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="],
"browserslist/baseline-browser-mapping": ["baseline-browser-mapping@2.8.10", "", { "bin": { "baseline-browser-mapping": "dist/cli.js" } }, "sha512-uLfgBi+7IBNay8ECBO2mVMGZAc1VgZWEChxm4lv+TobGdG82LnXMjuNGo/BSSZZL4UmkWhxEHP2f5ziLNwGWMA=="],
"chokidar/glob-parent": ["glob-parent@5.1.2", "", { "dependencies": { "is-glob": "^4.0.1" } }, "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow=="],
"engine.io-client/debug": ["debug@4.3.7", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ=="],
+4
View File
@@ -1,10 +1,12 @@
{
"lockfileVersion": 1,
"configVersion": 0,
"workspaces": {
"": {
"name": "strem.graff.tech-session-server",
"dependencies": {
"got": "^14.4.9",
"tree-kill": "^1.2.2",
},
"devDependencies": {
"bun-types": "latest",
@@ -66,6 +68,8 @@
"responselike": ["responselike@3.0.0", "", { "dependencies": { "lowercase-keys": "^3.0.0" } }, "sha512-40yHxbNcl2+rzXvZuVkrYohathsSJlMTXKryG5y8uciHv1+xDLHQpgjG64JUO9nrEq2jGLH6IZ8BcZyw3wrweg=="],
"tree-kill": ["tree-kill@1.2.2", "", { "bin": { "tree-kill": "cli.js" } }, "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A=="],
"type-fest": ["type-fest@4.41.0", "", {}, "sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA=="],
"undici-types": ["undici-types@7.14.0", "", {}, "sha512-QQiYxHuyZ9gQUIrmPo3IA+hUl4KYk8uSA7cHrcKd/l3p1OTpZcM0Tbp9x7FAtXdAYhlasd60ncPpgu6ihG6TOA=="],
+2 -1
View File
@@ -12,6 +12,7 @@
"start": "bun ./dist/index.js"
},
"dependencies": {
"got": "^14.4.9"
"got": "^14.4.9",
"tree-kill": "^1.2.2"
}
}
Binary file not shown.
+57 -86
View File
@@ -5,6 +5,8 @@ import { existsSync } from "fs";
import { createServer } from "net";
import { fileURLToPath } from "url";
import { dirname, join } from "path";
// @ts-ignore - tree-kill не имеет типов
import treeKill from "tree-kill";
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
@@ -593,7 +595,7 @@ async function startApplication(session: SessionData): Promise<void> {
console.log(
`[${new Date().toISOString()}] 🛑 Остановка Cirrus для завершённой сессии ${sessionId}`
);
killProcessTree(cirrus.pid);
await killProcessTree(cirrus.pid);
activeCirrusProcesses.delete(sessionId);
}
}
@@ -620,7 +622,7 @@ async function startApplication(session: SessionData): Promise<void> {
if (mode === "stream") {
const cirrus = activeCirrusProcesses.get(sessionId);
if (cirrus && cirrus.pid) {
killProcessTree(cirrus.pid);
await killProcessTree(cirrus.pid);
activeCirrusProcesses.delete(sessionId);
}
}
@@ -672,7 +674,7 @@ async function startApplication(session: SessionData): Promise<void> {
if (mode === "stream") {
const cirrus = activeCirrusProcesses.get(sessionId);
if (cirrus && cirrus.pid) {
killProcessTree(cirrus.pid);
await killProcessTree(cirrus.pid);
activeCirrusProcesses.delete(sessionId);
}
}
@@ -685,74 +687,59 @@ async function startApplication(session: SessionData): Promise<void> {
}
/**
* Убить процесс и всё его дерево дочерних процессов (для Windows)
* Принудительное завершение без попыток мягкого закрытия
* Убить процесс и всё его дерево дочерних процессов
* Использует tree-kill для надёжного завершения всего дерева процессов
*/
function killProcessTree(pid: number): void {
try {
// Принудительное завершение с /F
function killProcessTree(pid: number): Promise<void> {
return new Promise((resolve) => {
console.log(
`[${new Date().toISOString()}] 🔄 Принудительное завершение процесса PID ${pid}...`
);
execSync(`taskkill /pid ${pid} /T /F`, {
stdio: "ignore",
timeout: 30000, // Таймаут 30 секунд
windowsHide: true,
killSignal: "SIGKILL",
treeKill(pid, "SIGKILL", (err: Error | undefined) => {
if (err) {
// Проверяем, действительно ли процесс всё ещё существует
const processExists = checkProcessExists(pid);
if (!processExists) {
console.log(
`[${new Date().toISOString()}] ✅ Процесс PID ${pid} уже завершён`
);
resolve();
return;
}
console.error(
`[${new Date().toISOString()}] ⚠️ Ошибка при завершении дерева процессов PID ${pid}:`,
err.message
);
// Fallback: попытка через taskkill
try {
console.log(
`[${new Date().toISOString()}] 🔄 Попытка завершения через taskkill для PID ${pid}`
);
execSync(`taskkill /pid ${pid} /T /F`, {
stdio: "ignore",
timeout: 10000,
windowsHide: true,
});
console.log(
`[${new Date().toISOString()}] ✅ Процесс PID ${pid} завершён через taskkill`
);
} catch (fallbackErr) {
console.error(
`[${new Date().toISOString()}] ❌ Не удалось завершить процесс PID ${pid}:`,
fallbackErr instanceof Error ? fallbackErr.message : fallbackErr
);
}
} else {
console.log(
`[${new Date().toISOString()}] ✅ Дерево процессов для PID ${pid} успешно завершено`
);
}
resolve();
});
console.log(
`[${new Date().toISOString()}] ✅ Дерево процессов для PID ${pid} успешно завершено принудительно`
);
} catch (error) {
// Проверяем, действительно ли процесс всё ещё существует
const processExists = checkProcessExists(pid);
if (!processExists) {
console.log(
`[${new Date().toISOString()}] ✅ Процесс PID ${pid} уже завершён`
);
return;
}
console.error(
`[${new Date().toISOString()}] ⚠️ Ошибка при завершении дерева процессов PID ${pid}:`,
error instanceof Error ? error.message : error
);
// Попытка принудительного завершения через PowerShell как последний вариант
try {
console.log(
`[${new Date().toISOString()}] 🔄 Попытка принудительного завершения через PowerShell для PID ${pid}`
);
// Используем агрессивный PowerShell скрипт для принудительного завершения
const psScript = `
$proc = Get-Process -Id ${pid} -ErrorAction SilentlyContinue;
if ($proc) {
# Принудительно завершаем процесс и все дочерние
Stop-Process -Id ${pid} -Force -ErrorAction SilentlyContinue;
# Завершаем все дочерние процессы
Get-Process | Where-Object { $_.Parent.Id -eq ${pid} } | Stop-Process -Force -ErrorAction SilentlyContinue;
}
`.replace(/\n/g, " ");
execSync(
`powershell -Command "${psScript}"`,
{
stdio: "ignore",
timeout: 15000,
windowsHide: true,
}
);
console.log(
`[${new Date().toISOString()}] ✅ Процесс PID ${pid} завершён через PowerShell`
);
} catch (psError) {
console.error(
`[${new Date().toISOString()}] ❌ Не удалось завершить процесс PID ${pid} даже через PowerShell:`,
psError instanceof Error ? psError.message : psError
);
}
}
});
}
/**
@@ -822,16 +809,7 @@ async function stopApplication(session: SessionData): Promise<void> {
// Останавливаем UE приложение
const pidToKill = appPid || appProcess?.pid;
if (pidToKill) {
killPromises.push(
new Promise<void>((resolve) => {
// Запускаем killProcessTree в отдельном потоке через setTimeout
// чтобы не блокировать основной поток
setTimeout(() => {
killProcessTree(pidToKill);
resolve();
}, 0);
})
);
killPromises.push(killProcessTree(pidToKill));
} else {
console.warn(
`[${new Date().toISOString()}] ⚠️ Не удалось получить PID приложения для сессии ${sessionId}`
@@ -842,14 +820,7 @@ async function stopApplication(session: SessionData): Promise<void> {
if (mode === "stream") {
const cirrusPidToKill = cirrusPid || cirrusProcess?.pid;
if (cirrusPidToKill) {
killPromises.push(
new Promise<void>((resolve) => {
setTimeout(() => {
killProcessTree(cirrusPidToKill);
resolve();
}, 0);
})
);
killPromises.push(killProcessTree(cirrusPidToKill));
} else {
console.warn(
`[${new Date().toISOString()}] ⚠️ Не удалось получить PID Cirrus для сессии ${sessionId}`
@@ -1011,14 +982,14 @@ async function checkSessions(): Promise<void> {
`[${new Date().toISOString()}] ⚠️ Найден процесс для неактивной сессии ${sessionId}, остановка`
);
if (process.pid) {
killProcessTree(process.pid);
await killProcessTree(process.pid);
}
activeProcesses.delete(sessionId);
// Также останавливаем Cirrus если есть
const cirrusProcess = activeCirrusProcesses.get(sessionId);
if (cirrusProcess && cirrusProcess.pid) {
killProcessTree(cirrusProcess.pid);
await killProcessTree(cirrusProcess.pid);
activeCirrusProcesses.delete(sessionId);
}
}
-51
View File
@@ -1,51 +0,0 @@
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name stream.graff.estate;
root /var/www/stream.graff.estate/client/dist;
# SSL
ssl_certificate /etc/letsencrypt/live/stream.graff.estate/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/stream.graff.estate/privkey.pem;
ssl_trusted_certificate /etc/letsencrypt/live/stream.graff.estate/chain.pem;
# security
include nginxconfig.io/security.conf;
# logging
access_log /var/log/nginx/access.log combined buffer=512k flush=1m;
error_log /var/log/nginx/error.log warn;
# index.html fallback
location / {
try_files $uri $uri/ /index.html;
}
location /api {
rewrite ^/api/(.*)$ /$1 break;
proxy_pass http://127.0.0.1:6000;
proxy_set_header Host $host;
include nginxconfig.io/proxy.conf;
}
location /socket.io {
proxy_pass http://127.0.0.1:6001;
proxy_set_header Host $host;
include nginxconfig.io/proxy.conf;
}
# additional config
include nginxconfig.io/general.conf;
}
# HTTP redirect
server {
listen 80;
listen [::]:80;
server_name stream.graff.estate;
include nginxconfig.io/letsencrypt.conf;
location / {
return 301 https://stream.graff.estate$request_uri;
}
}