- Added support for launching applications without a graphical window using `-NOSPLASH` and `-NOWINDOW` flags. - Improved process termination logic with a multi-step approach: soft termination, forced termination, and PowerShell fallback. - Updated README to reflect new features and enhancements in process management.
21 KiB
Session Server
Сессионный сервер для автоматической регистрации на основном API сервере.
Описание
Session Server - это приложение, которое автоматически регистрируется на основном сервере (stream.graff.tech) и периодически обновляет свою информацию. Это позволяет основному серверу знать о доступных сессионных серверах для распределения нагрузки.
Возможности
- 🚀 Автоматическая регистрация при запуске
- 🔄 Периодическое обновление информации о сервере (по умолчанию каждые 30 секунд после завершения предыдущего запроса)
- 🎮 Автоматическое определение и обновление свободной GPU памяти через nvidia-smi (по умолчанию каждую секунду после завершения предыдущего запроса)
- 🎯 Автоматическое управление игровыми сессиями
- Запуск приложений для сессий со статусом "starting"
- Остановка приложений для сессий со статусом "ending"
- Отслеживание PID запущенных процессов
- Автоматическое обновление статусов сессий на главном сервере
- 🌐 Автоматическое определение локального IP адреса
- 💻 Автоматическое определение hostname
- ⚙️ Гибкая конфигурация через переменные окружения
- 🔁 Автоматические повторные попытки при ошибках
- 📝 Подробное логирование
- ⚡ Защита от наложения запросов для всех операций (рекурсивный вызов через setTimeout)
Установка
# Установка зависимостей
bun install
Конфигурация
Создайте файл .env в корне проекта на основе .env.example:
# URL основного API сервера
API_URL=http://localhost:3000
# Тип сервера: stream или local
SERVER_TYPE=stream
# Расположение сервера (ОБЯЗАТЕЛЬНО для stream серверов)
# Возможные значения: ru1, uae1
SERVER_LOCATION=ru1
# Уровень сервера (только для stream серверов)
# Возможные значения: demo, prod
SERVER_TIER=demo
# ID филиала (ОБЯЗАТЕЛЬНО для local серверов)
BRANCH_ID=00000000-0000-0000-0000-000000000000
# Локальный IP адрес (опционально, определяется автоматически)
# LOCAL_IP=192.168.1.100
# Hostname сервера (опционально, определяется автоматически)
# HOSTNAME=my-session-server
# Интервал регистрации в миллисекундах (по умолчанию 30000 = 30 секунд)
REGISTER_INTERVAL_MS=30000
# Интервал обновления GPU памяти в миллисекундах (по умолчанию 1000 = 1 секунда)
GPU_UPDATE_INTERVAL_MS=1000
# Интервал проверки сессий в миллисекундах (по умолчанию 5000 = 5 секунд)
SESSION_CHECK_INTERVAL_MS=5000
Переменные окружения
| Переменная | Описание | Обязательна | По умолчанию |
|---|---|---|---|
API_URL |
URL основного API сервера | Нет | http://localhost:3000 |
SERVER_TYPE |
Тип сервера (stream или local) |
Нет | stream |
SERVER_LOCATION |
Расположение (ru1, uae1) - обязательно для stream |
Да (для stream) | - |
SERVER_TIER |
Уровень (demo, prod) - только для stream |
Нет | demo (для stream) |
BRANCH_ID |
ID филиала - обязательно для local |
Да (для local) | - |
LOCAL_IP |
Локальный IP адрес | Нет | Определяется автоматически |
HOSTNAME |
Hostname сервера | Нет | Определяется автоматически |
REGISTER_INTERVAL_MS |
Интервал регистрации в мс | Нет | 30000 |
GPU_UPDATE_INTERVAL_MS |
Интервал обновления GPU памяти в мс | Нет | 1000 |
SESSION_CHECK_INTERVAL_MS |
Интервал проверки сессий в мс | Нет | 5000 |
Примечание: Свободная память GPU (gpuFreeMb) автоматически определяется через nvidia-smi при каждой регистрации и обновляется каждую секунду (или согласно GPU_UPDATE_INTERVAL_MS) после завершения предыдущего запроса. Это предотвращает наложение запросов. Если nvidia-smi недоступен, сервер завершит работу с ошибкой.
Управление сессиями
Session Server автоматически управляет игровыми сессиями на этом сервере:
Как это работает
- Проверка сессий: Каждую секунду (или согласно
SESSION_CHECK_INTERVAL_MS) сервер запрашивает у основного API список сессий для этого сервера - Проверка времени окончания: Для активных сессий (
startedилиstarting):- ⏰ Проверяется время
endAt- если оно наступило, сессия автоматически переводится в статусending - Timezone: Все время хранится в UTC, сравнение корректно работает независимо от часового пояса сервера
- По умолчанию сессии создаются с временем окончания +30 минут от момента создания
- Автоматическое завершение гарантирует, что сессии не будут работать бесконечно
- ⏰ Проверяется время
- Запуск приложений: Для сессий со статусом
starting:- ⏰ Проверяется время
startAt- приложение запускается только если это время уже наступило - Timezone: Все время хранится в UTC, сравнение корректно работает независимо от часового пояса сервера
- Запланированные сессии (с будущим
startAt) логируются с информацией о времени до запуска - 🎯 Централизованное назначение сервера (для stream-сессий):
- Main server автоматически назначает серверы каждые 5 секунд
- Выбирается сервер с максимальной свободной GPU памятью
- Учитываются требования приложения к GPU памяти (
gpuLimitMb) - Session-server просто проверяет, что сессия назначена ему
- Запускается соответствующее приложение
- Отслеживается PID процесса
- Статус сессии обновляется на
startedна главном сервере
- ⏰ Проверяется время
- Остановка приложений: Для сессий со статусом
ending:- Используется
taskkill /pid {PID} /T /Fдля завершения всего дерева процессов /T- завершает указанный процесс и ВСЕ дочерние процессы/F- принудительное завершение- Решает проблему с UE5 и другими приложениями, создающими дочерние процессы
- Статус сессии обновляется на
endedна главном сервере
- Используется
- Автоматическая очистка: Процессы для неактивных сессий автоматически останавливаются
API endpoints для управления сессиями
Session Server взаимодействует с основным сервером через следующие endpoints:
GET /servers/:id/sessions- получить список сессий для сервераPATCH /sessions/:id/status- обновить статус сессии (публичный endpoint)
Запуск приложений
Session Server автоматически запускает .exe приложения по стандартному пути:
C:\apps\{appName}\{appName}.exe
Где {appName} - это значение поля name из таблицы apps.
Структура директорий
Все приложения должны быть размещены в следующей структуре:
C:\apps\
├── minecraft\
│ └── minecraft.exe
├── fortnite\
│ └── fortnite.exe
└── cyberpunk\
└── cyberpunk.exe
Особенности запуска и остановки
- ✅ Автоматическая проверка существования exe файла
- ✅ Рабочая директория устанавливается в папку приложения (
C:\apps\{appName}\) - ✅ Окно консоли скрывается (
windowsHide: true) - ✅ Запуск без графического окна - использует флаги
-NOSPLASHи-NOWINDOWдля UE приложений - ✅ PID процесса отслеживается и передается на main server
- ✅ Автоматическое обновление статуса при завершении процесса
- ✅ Многоступенчатое завершение процессов:
- Мягкое завершение (
taskkill /T) - отправляет WM_CLOSE сообщение окнам - Принудительное завершение (
taskkill /T /F) - если мягкое не сработало - PowerShell завершение - закрывает окна и убивает процесс через PowerShell
- Мягкое завершение (
- ✅ Решает проблему с UE5 приложениями, которые создают множественные процессы и имеют графические окна
Логи запуска
[2025-10-06T10:00:00.000Z] 🚀 Запуск приложения "minecraft" для сессии abc-123
[2025-10-06T10:00:00.050Z] 📂 Путь к приложению: C:\apps\minecraft\minecraft.exe
[2025-10-06T10:00:01.000Z] ✅ Приложение запущено с PID 12345
[2025-10-06T10:00:01.100Z] ✅ Статус сессии abc-123 обновлен на "started"
Обработка ошибок
Если exe файл не найден:
❌ Файл приложения не найден: C:\apps\minecraft\minecraft.exe. Убедитесь, что приложение установлено.
Примеры логов
Запланированная сессия:
[2025-10-06T10:00:00.000Z] ⏰ Сессия 123e4567-e89b-12d3-a456-426614174000 (minecraft) запланирована через 120 сек
Запуск сессии:
[2025-10-06T10:02:00.000Z] 🚀 Запуск приложения "minecraft" для сессии 123e4567-e89b-12d3-a456-426614174000
[2025-10-06T10:02:01.000Z] ✅ Приложение запущено с PID 12345
[2025-10-06T10:02:01.100Z] ✅ Статус сессии 123e4567-e89b-12d3-a456-426614174000 обновлен на "started"
Автоматическое завершение по истечении времени:
[2025-10-06T10:32:00.000Z] ⏰ Время сессии 123e4567-e89b-12d3-a456-426614174000 (minecraft) истекло, завершение...
[2025-10-06T10:32:00.100Z] ✅ Статус сессии 123e4567-e89b-12d3-a456-426614174000 обновлен на "ending"
Остановка сессии:
[2025-10-06T10:32:00.000Z] 🛑 Остановка приложения для сессии 123e4567-e89b-12d3-a456-426614174000 (PID: 12345)
[2025-10-06T10:32:00.500Z] ✅ Дерево процессов для PID 12345 успешно завершено
[2025-10-06T10:32:00.600Z] ✅ Приложение и все дочерние процессы остановлены для сессии 123e4567-e89b-12d3-a456-426614174000
[2025-10-06T10:32:00.700Z] ✅ Статус сессии 123e4567-e89b-12d3-a456-426614174000 обновлен на "ended"
Отладка проблем (Troubleshooting)
Если приложение запускается и сразу завершается с ошибкой, см. подробное руководство по диагностике:
Новые возможности логирования
После обновления вы увидите:
- 🔴 STDERR логи для диагностики ошибок приложений
- 📊 Счётчик активных процессов при запуске/завершении
- ⚠️ Детальная информация о кодах выхода и сигналах
Пример логов с ошибкой:
[10:51:56.498Z] 🚀 Запуск приложения "ShishimGorka" для сессии abc (активных процессов: 1)
[10:51:56.563Z] ✅ Приложение запущено с PID 84112 (всего активных: 2)
[10:51:57.500Z] 🔴 STDERR [abc]: Error: Port 8888 is already in use
[10:51:57.894Z] 🛑 Приложение для сессии abc завершилось с кодом 1
[10:51:57.894Z] ⚠️ Приложение завершилось с ошибкой! Код выхода: 1
Работа с часовыми поясами (Timezone)
Session Server корректно работает с разными часовыми поясами:
Как это работает
- База данных: PostgreSQL хранит все timestamp с timezone в UTC
- API: Основной сервер возвращает время в формате ISO 8601 с timezone (например,
2025-10-06T10:00:00.000Z) - Session Server: JavaScript автоматически парсит ISO 8601 строки в UTC
- Сравнение: Все сравнения времени происходят в UTC, независимо от локального часового пояса сервера
Миграция базы данных
⚠️ Важно: Если вы обновляете существующую систему, необходимо выполнить миграцию для добавления timezone в поля startAt и endAt:
# Из директории server/
psql -d $DATABASE_URL -f timezone_migration.sql
См. server/TIMEZONE_MIGRATION.md для подробностей.
Примеры
Если сервер в России создаёт сессию на 14:00 по московскому времени (UTC+3):
- В БД сохранится:
2025-10-06T11:00:00.000Z(UTC) - Сервер в ОАЭ (UTC+4) увидит: 15:00 по местному времени
- Session Server запустит приложение ровно в 11:00 UTC, независимо от локального времени
Запуск
Development режим
bun run dev
Production режим
# Собрать проект
bun run build
# Запустить собранное приложение
bun run start
Примеры использования
Stream сервер в России (демо)
API_URL=https://api.stream.graff.tech
SERVER_TYPE=stream
SERVER_LOCATION=ru1
SERVER_TIER=demo
REGISTER_INTERVAL_MS=30000
Stream сервер в ОАЭ (продакшн)
API_URL=https://api.stream.graff.tech
SERVER_TYPE=stream
SERVER_LOCATION=uae1
SERVER_TIER=prod
REGISTER_INTERVAL_MS=30000
Local сервер для филиала
API_URL=https://api.stream.graff.tech
SERVER_TYPE=local
BRANCH_ID=123e4567-e89b-12d3-a456-426614174000
REGISTER_INTERVAL_MS=60000
Логирование
Сервер выводит подробную информацию о своей работе:
============================================================
🚀 Запуск сессионного сервера
============================================================
Конфигурация:
API URL: http://localhost:3000
Hostname: DESKTOP-ABC123
Local IP: 192.168.1.100
Type: stream
GPU Free MB: 8192 (читается из nvidia-smi)
Location: ru1
Tier: demo
Register Interval: 30000ms
GPU Update Interval: 1000ms
============================================================
[2025-10-06T12:00:00.000Z] Регистрация сервера...
Данные: {
"localIp": "192.168.1.100",
"hostname": "DESKTOP-ABC123",
"type": "stream",
"gpuFreeMb": 8192,
"location": "ru1",
"tier": "demo"
}
[2025-10-06T12:00:00.123Z] ✅ Сервер успешно зарегистрирован
ID сервера: 123e4567-e89b-12d3-a456-426614174000
[2025-10-06T12:00:01.000Z] 🎮 GPU память обновлена: 8150 MB
[2025-10-06T12:00:02.000Z] 🎮 GPU память обновлена: 8120 MB
[2025-10-06T12:00:03.000Z] 🎮 GPU память обновлена: 8100 MB
Обработка ошибок
Сервер автоматически обрабатывает ошибки:
- Валидация конфигурации:
- Stream-серверы: обязательно должен быть указан
SERVER_LOCATION - Local-серверы: обязательно должен быть указан
BRANCH_ID - При отсутствии обязательных полей сервер завершит работу с критической ошибкой
- Stream-серверы: обязательно должен быть указан
- Сетевые ошибки: Автоматические повторные попытки (до 3 раз)
- Таймауты: 10 секунд на запрос
- Коды ошибок: Повторная отправка при временных ошибках сервера (408, 429, 500, 502, 503, 504)
- Ошибки GPU: Если
nvidia-smiнедоступен или возвращает некорректные данные, сервер завершит работу с критической ошибкой - Критические ошибки: Подробное логирование с завершением работы
Архитектура
┌──────────────────────────────────┐
│ Session Server │
│ │
│ Регистрация (рекурсивно): │
│ 1. Определение IP │
│ 2. Определение hostname │
│ 3. Запрос GPU (nvidia-smi) │
│ 4. POST /servers/register │
│ 5. setTimeout → повтор (30s) │
│ │
│ Обновление GPU (рекурсивно): │
│ 1. Запрос GPU (nvidia-smi) │
│ 2. PATCH /servers/:id/gpu │
│ 3. setTimeout → повтор (1s) │
└──────────┬───────────────────────┘
│
│ HTTP Requests
│
▼
┌──────────────────────────────────┐
│ Main API Server │
│ │
│ 1. Проверка по hostname │
│ 2. Создание/обновление │
│ 3. Обновление GPU памяти │
│ 4. Возврат данных │
└──────────────────────────────────┘
Разработка
Структура проекта
session-server/
├── src/
│ └── index.ts # Основной файл приложения
├── dist/ # Собранное приложение
├── package.json
├── tsconfig.json
├── bun.build.ts # Конфигурация сборки
└── README.md
Требования
- Bun >= 1.0
- Node.js >= 18 (опционально)
- TypeScript >= 5.0
- NVIDIA GPU с установленным
nvidia-smi(обязательно)
Лицензия
MIT