v1.3.2
This commit is contained in:
29
.gitignore
vendored
29
.gitignore
vendored
@@ -3,4 +3,31 @@
|
|||||||
bin
|
bin
|
||||||
lib
|
lib
|
||||||
|
|
||||||
rabota_today.db
|
rabota_today.db
|
||||||
|
|
||||||
|
# Логи сервера
|
||||||
|
server.log
|
||||||
|
server_error.log
|
||||||
|
server.pid
|
||||||
|
|
||||||
|
# Python
|
||||||
|
__pycache__/
|
||||||
|
*.py[cod]
|
||||||
|
*$py.class
|
||||||
|
*.so
|
||||||
|
.Python
|
||||||
|
venv/
|
||||||
|
.venv/
|
||||||
|
env/
|
||||||
|
.env
|
||||||
|
|
||||||
|
# База данных
|
||||||
|
*.db
|
||||||
|
*.db-journal
|
||||||
|
|
||||||
|
# IDE
|
||||||
|
.vscode/
|
||||||
|
.idea/
|
||||||
|
*.swp
|
||||||
|
*.swo
|
||||||
|
*~
|
||||||
247
server.sh
Executable file
247
server.sh
Executable file
@@ -0,0 +1,247 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# server.sh - Bash скрипт для управления сервером
|
||||||
|
|
||||||
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
|
PID_FILE="$SCRIPT_DIR/server.pid"
|
||||||
|
LOG_FILE="$SCRIPT_DIR/server.log"
|
||||||
|
ERROR_LOG="$SCRIPT_DIR/server_error.log"
|
||||||
|
PYTHON_CMD="python3"
|
||||||
|
SERVER_SCRIPT="main.py"
|
||||||
|
|
||||||
|
# Цвета для вывода
|
||||||
|
RED='\033[0;31m'
|
||||||
|
GREEN='\033[0;32m'
|
||||||
|
YELLOW='\033[1;33m'
|
||||||
|
BLUE='\033[0;34m'
|
||||||
|
NC='\033[0m' # No Color
|
||||||
|
|
||||||
|
# Функция для вывода сообщений
|
||||||
|
log_info() {
|
||||||
|
echo -e "${BLUE}[INFO]${NC} $1"
|
||||||
|
}
|
||||||
|
|
||||||
|
log_success() {
|
||||||
|
echo -e "${GREEN}[SUCCESS]${NC} $1"
|
||||||
|
}
|
||||||
|
|
||||||
|
log_warning() {
|
||||||
|
echo -e "${YELLOW}[WARNING]${NC} $1"
|
||||||
|
}
|
||||||
|
|
||||||
|
log_error() {
|
||||||
|
echo -e "${RED}[ERROR]${NC} $1"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Проверка, запущен ли сервер
|
||||||
|
is_running() {
|
||||||
|
if [ -f "$PID_FILE" ]; then
|
||||||
|
PID=$(cat "$PID_FILE")
|
||||||
|
if ps -p "$PID" > /dev/null 2>&1; then
|
||||||
|
return 0
|
||||||
|
else
|
||||||
|
rm -f "$PID_FILE"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
# Получить PID
|
||||||
|
get_pid() {
|
||||||
|
if [ -f "$PID_FILE" ]; then
|
||||||
|
cat "$PID_FILE"
|
||||||
|
else
|
||||||
|
echo ""
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Запуск сервера
|
||||||
|
start() {
|
||||||
|
if is_running; then
|
||||||
|
log_error "Сервер уже запущен (PID: $(get_pid))"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
log_info "Запуск сервера в фоновом режиме..."
|
||||||
|
|
||||||
|
cd "$SCRIPT_DIR" || exit 1
|
||||||
|
|
||||||
|
# Запускаем в фоне
|
||||||
|
nohup $PYTHON_CMD $SERVER_SCRIPT >> "$LOG_FILE" 2>> "$ERROR_LOG" &
|
||||||
|
PID=$!
|
||||||
|
|
||||||
|
echo $PID > "$PID_FILE"
|
||||||
|
|
||||||
|
# Ждем немного
|
||||||
|
sleep 2
|
||||||
|
|
||||||
|
if is_running; then
|
||||||
|
log_success "Сервер запущен (PID: $PID)"
|
||||||
|
log_info "Логи: $LOG_FILE"
|
||||||
|
log_info "Логи ошибок: $ERROR_LOG"
|
||||||
|
return 0
|
||||||
|
else
|
||||||
|
log_error "Сервер не запустился"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Остановка сервера
|
||||||
|
stop() {
|
||||||
|
if ! is_running; then
|
||||||
|
log_error "Сервер не запущен"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
PID=$(get_pid)
|
||||||
|
log_info "Остановка сервера (PID: $PID)..."
|
||||||
|
|
||||||
|
# Пытаемся остановить gracefully
|
||||||
|
kill -TERM "$PID" 2>/dev/null
|
||||||
|
|
||||||
|
# Ждем завершения
|
||||||
|
for i in {1..10}; do
|
||||||
|
if ! is_running; then
|
||||||
|
log_success "Сервер остановлен"
|
||||||
|
rm -f "$PID_FILE"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
sleep 1
|
||||||
|
done
|
||||||
|
|
||||||
|
# Если не остановился, принудительно завершаем
|
||||||
|
log_warning "Сервер не отвечает, принудительное завершение..."
|
||||||
|
kill -KILL "$PID" 2>/dev/null
|
||||||
|
sleep 1
|
||||||
|
|
||||||
|
if ! is_running; then
|
||||||
|
log_success "Сервер принудительно остановлен"
|
||||||
|
rm -f "$PID_FILE"
|
||||||
|
return 0
|
||||||
|
else
|
||||||
|
log_error "Не удалось остановить сервер"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Перезапуск
|
||||||
|
restart() {
|
||||||
|
log_info "Перезапуск сервера..."
|
||||||
|
stop
|
||||||
|
sleep 2
|
||||||
|
start
|
||||||
|
}
|
||||||
|
|
||||||
|
# Статус
|
||||||
|
status() {
|
||||||
|
if is_running; then
|
||||||
|
PID=$(get_pid)
|
||||||
|
log_success "Сервер запущен (PID: $PID)"
|
||||||
|
|
||||||
|
# Показываем использование ресурсов
|
||||||
|
if command -v ps &> /dev/null; then
|
||||||
|
ps -p "$PID" -o pid,ppid,cmd,%mem,%cpu,etime
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Показываем последние строки лога
|
||||||
|
if [ -f "$LOG_FILE" ]; then
|
||||||
|
echo ""
|
||||||
|
log_info "Последние строки лога:"
|
||||||
|
tail -5 "$LOG_FILE" | while read line; do
|
||||||
|
echo " $line"
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
log_error "Сервер не запущен"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Показать логи
|
||||||
|
logs() {
|
||||||
|
lines=${1:-20}
|
||||||
|
if [ -f "$LOG_FILE" ]; then
|
||||||
|
echo "📋 Последние $lines строк лога:"
|
||||||
|
echo "----------------------------------------"
|
||||||
|
tail -n "$lines" "$LOG_FILE"
|
||||||
|
else
|
||||||
|
log_error "Лог файл не найден"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Показать ошибки
|
||||||
|
errors() {
|
||||||
|
lines=${1:-20}
|
||||||
|
if [ -f "$ERROR_LOG" ]; then
|
||||||
|
echo "⚠️ Последние $lines строк лога ошибок:"
|
||||||
|
echo "----------------------------------------"
|
||||||
|
tail -n "$lines" "$ERROR_LOG"
|
||||||
|
else
|
||||||
|
log_info "Лог ошибок не найден"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Очистить логи
|
||||||
|
clear_logs() {
|
||||||
|
if [ -f "$LOG_FILE" ]; then
|
||||||
|
> "$LOG_FILE"
|
||||||
|
log_success "Лог очищен"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -f "$ERROR_LOG" ]; then
|
||||||
|
> "$ERROR_LOG"
|
||||||
|
log_success "Лог ошибок очищен"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Мониторинг в реальном времени
|
||||||
|
monitor() {
|
||||||
|
if ! is_running; then
|
||||||
|
log_error "Сервер не запущен"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
log_info "Мониторинг сервера (Ctrl+C для выхода)..."
|
||||||
|
tail -f "$LOG_FILE"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Основная логика
|
||||||
|
case "$1" in
|
||||||
|
start)
|
||||||
|
start
|
||||||
|
;;
|
||||||
|
stop)
|
||||||
|
stop
|
||||||
|
;;
|
||||||
|
restart)
|
||||||
|
restart
|
||||||
|
;;
|
||||||
|
status)
|
||||||
|
status
|
||||||
|
;;
|
||||||
|
logs)
|
||||||
|
logs "$2"
|
||||||
|
;;
|
||||||
|
errors)
|
||||||
|
errors "$2"
|
||||||
|
;;
|
||||||
|
clear-logs)
|
||||||
|
clear_logs
|
||||||
|
;;
|
||||||
|
monitor)
|
||||||
|
monitor
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo "Использование: $0 {start|stop|restart|status|logs|errors|clear-logs|monitor}"
|
||||||
|
echo ""
|
||||||
|
echo "Команды:"
|
||||||
|
echo " start - запустить сервер в фоне"
|
||||||
|
echo " stop - остановить сервер"
|
||||||
|
echo " restart - перезапустить сервер"
|
||||||
|
echo " status - показать статус сервера"
|
||||||
|
echo " logs [N] - показать последние N строк лога (по умолчанию 20)"
|
||||||
|
echo " errors [N] - показать последние N строк лога ошибок"
|
||||||
|
echo " clear-logs - очистить логи"
|
||||||
|
echo " monitor - мониторинг логов в реальном времени"
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
230
server_manager.py
Normal file
230
server_manager.py
Normal file
@@ -0,0 +1,230 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
# server_manager.py - Скрипт для управления сервером в фоновом режиме
|
||||||
|
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import signal
|
||||||
|
import subprocess
|
||||||
|
import time
|
||||||
|
import atexit
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
# Конфигурация
|
||||||
|
PID_FILE = "server.pid"
|
||||||
|
LOG_FILE = "server.log"
|
||||||
|
ERROR_LOG = "server_error.log"
|
||||||
|
PYTHON_CMD = sys.executable
|
||||||
|
SERVER_SCRIPT = "server.py"
|
||||||
|
|
||||||
|
|
||||||
|
class ServerManager:
|
||||||
|
def __init__(self):
|
||||||
|
self.pid_file = Path(PID_FILE)
|
||||||
|
self.log_file = Path(LOG_FILE)
|
||||||
|
self.error_log = Path(ERROR_LOG)
|
||||||
|
|
||||||
|
def is_running(self):
|
||||||
|
"""Проверка, запущен ли сервер"""
|
||||||
|
if not self.pid_file.exists():
|
||||||
|
return False
|
||||||
|
|
||||||
|
try:
|
||||||
|
with open(self.pid_file, 'r') as f:
|
||||||
|
pid = int(f.read().strip())
|
||||||
|
|
||||||
|
# Проверяем, существует ли процесс
|
||||||
|
os.kill(pid, 0)
|
||||||
|
return True
|
||||||
|
except (OSError, ValueError, ProcessLookupError):
|
||||||
|
# PID файл существует, но процесс не найден
|
||||||
|
self.pid_file.unlink(missing_ok=True)
|
||||||
|
return False
|
||||||
|
|
||||||
|
def get_pid(self):
|
||||||
|
"""Получить PID сервера"""
|
||||||
|
if not self.pid_file.exists():
|
||||||
|
return None
|
||||||
|
|
||||||
|
try:
|
||||||
|
with open(self.pid_file, 'r') as f:
|
||||||
|
return int(f.read().strip())
|
||||||
|
except:
|
||||||
|
return None
|
||||||
|
|
||||||
|
def start(self):
|
||||||
|
"""Запуск сервера в фоновом режиме"""
|
||||||
|
if self.is_running():
|
||||||
|
print(f"❌ Сервер уже запущен (PID: {self.get_pid()})")
|
||||||
|
return False
|
||||||
|
|
||||||
|
print("🚀 Запуск сервера в фоновом режиме...")
|
||||||
|
|
||||||
|
try:
|
||||||
|
# Открываем файлы для логов
|
||||||
|
log_fd = open(self.log_file, 'a')
|
||||||
|
err_fd = open(self.error_log, 'a')
|
||||||
|
|
||||||
|
# Запускаем процесс
|
||||||
|
process = subprocess.Popen(
|
||||||
|
[PYTHON_CMD, SERVER_SCRIPT],
|
||||||
|
stdout=log_fd,
|
||||||
|
stderr=err_fd,
|
||||||
|
stdin=subprocess.DEVNULL,
|
||||||
|
start_new_session=True, # Отдельная сессия для фонового процесса
|
||||||
|
cwd=os.path.dirname(os.path.abspath(__file__))
|
||||||
|
)
|
||||||
|
|
||||||
|
# Сохраняем PID
|
||||||
|
with open(self.pid_file, 'w') as f:
|
||||||
|
f.write(str(process.pid))
|
||||||
|
|
||||||
|
# Небольшая задержка для проверки запуска
|
||||||
|
time.sleep(2)
|
||||||
|
|
||||||
|
if self.is_running():
|
||||||
|
print(f"✅ Сервер успешно запущен (PID: {process.pid})")
|
||||||
|
print(f"📝 Логи: {self.log_file}")
|
||||||
|
print(f"❌ Логи ошибок: {self.error_log}")
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
print("❌ Сервер не запустился")
|
||||||
|
return False
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"❌ Ошибка при запуске: {e}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
def stop(self):
|
||||||
|
"""Остановка сервера"""
|
||||||
|
if not self.is_running():
|
||||||
|
print("❌ Сервер не запущен")
|
||||||
|
return False
|
||||||
|
|
||||||
|
pid = self.get_pid()
|
||||||
|
print(f"🛑 Остановка сервера (PID: {pid})...")
|
||||||
|
|
||||||
|
try:
|
||||||
|
# Отправляем SIGTERM
|
||||||
|
os.kill(pid, signal.SIGTERM)
|
||||||
|
|
||||||
|
# Ждем завершения
|
||||||
|
timeout = 10
|
||||||
|
for _ in range(timeout):
|
||||||
|
time.sleep(1)
|
||||||
|
if not self.is_running():
|
||||||
|
print("✅ Сервер остановлен")
|
||||||
|
self.pid_file.unlink(missing_ok=True)
|
||||||
|
return True
|
||||||
|
|
||||||
|
# Если не остановился, принудительно завершаем
|
||||||
|
print("⚠️ Сервер не отвечает, принудительное завершение...")
|
||||||
|
os.kill(pid, signal.SIGKILL)
|
||||||
|
time.sleep(1)
|
||||||
|
|
||||||
|
if not self.is_running():
|
||||||
|
print("✅ Сервер принудительно остановлен")
|
||||||
|
self.pid_file.unlink(missing_ok=True)
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
print("❌ Не удалось остановить сервер")
|
||||||
|
return False
|
||||||
|
|
||||||
|
except ProcessLookupError:
|
||||||
|
print("⚠️ Процесс не найден, удаляем PID файл")
|
||||||
|
self.pid_file.unlink(missing_ok=True)
|
||||||
|
return True
|
||||||
|
except Exception as e:
|
||||||
|
print(f"❌ Ошибка при остановке: {e}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
def restart(self):
|
||||||
|
"""Перезапуск сервера"""
|
||||||
|
print("🔄 Перезапуск сервера...")
|
||||||
|
if self.is_running():
|
||||||
|
self.stop()
|
||||||
|
time.sleep(2)
|
||||||
|
return self.start()
|
||||||
|
|
||||||
|
def status(self):
|
||||||
|
"""Статус сервера"""
|
||||||
|
if self.is_running():
|
||||||
|
pid = self.get_pid()
|
||||||
|
print(f"✅ Сервер запущен (PID: {pid})")
|
||||||
|
print(f"📝 Логи: {self.log_file} ({self.log_file.stat().st_size} bytes)")
|
||||||
|
print(
|
||||||
|
f"❌ Логи ошибок: {self.error_log} ({self.error_log.stat().st_size if self.error_log.exists() else 0} bytes)")
|
||||||
|
|
||||||
|
# Показываем последние строки лога
|
||||||
|
if self.log_file.exists():
|
||||||
|
print("\n📋 Последние строки лога:")
|
||||||
|
with open(self.log_file, 'r') as f:
|
||||||
|
lines = f.readlines()
|
||||||
|
for line in lines[-5:]:
|
||||||
|
print(f" {line.strip()}")
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
print("❌ Сервер не запущен")
|
||||||
|
return False
|
||||||
|
|
||||||
|
def logs(self, lines=20):
|
||||||
|
"""Показать последние строки лога"""
|
||||||
|
if not self.log_file.exists():
|
||||||
|
print("📝 Лог файл не найден")
|
||||||
|
return
|
||||||
|
|
||||||
|
print(f"📋 Последние {lines} строк лога:")
|
||||||
|
print("-" * 50)
|
||||||
|
with open(self.log_file, 'r') as f:
|
||||||
|
all_lines = f.readlines()
|
||||||
|
for line in all_lines[-lines:]:
|
||||||
|
print(line.strip())
|
||||||
|
|
||||||
|
def errors(self, lines=20):
|
||||||
|
"""Показать последние строки лога ошибок"""
|
||||||
|
if not self.error_log.exists():
|
||||||
|
print("❌ Лог ошибок не найден")
|
||||||
|
return
|
||||||
|
|
||||||
|
print(f"⚠️ Последние {lines} строк лога ошибок:")
|
||||||
|
print("-" * 50)
|
||||||
|
with open(self.error_log, 'r') as f:
|
||||||
|
all_lines = f.readlines()
|
||||||
|
for line in all_lines[-lines:]:
|
||||||
|
print(line.strip())
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
manager = ServerManager()
|
||||||
|
|
||||||
|
if len(sys.argv) < 2:
|
||||||
|
print("Использование:")
|
||||||
|
print(" python server_manager.py start - запустить сервер")
|
||||||
|
print(" python server_manager.py stop - остановить сервер")
|
||||||
|
print(" python server_manager.py restart - перезапустить сервер")
|
||||||
|
print(" python server_manager.py status - статус сервера")
|
||||||
|
print(" python server_manager.py logs - показать логи")
|
||||||
|
print(" python server_manager.py errors - показать ошибки")
|
||||||
|
return
|
||||||
|
|
||||||
|
command = sys.argv[1].lower()
|
||||||
|
|
||||||
|
if command == 'start':
|
||||||
|
manager.start()
|
||||||
|
elif command == 'stop':
|
||||||
|
manager.stop()
|
||||||
|
elif command == 'restart':
|
||||||
|
manager.restart()
|
||||||
|
elif command == 'status':
|
||||||
|
manager.status()
|
||||||
|
elif command == 'logs':
|
||||||
|
lines = int(sys.argv[2]) if len(sys.argv) > 2 else 20
|
||||||
|
manager.logs(lines)
|
||||||
|
elif command == 'errors':
|
||||||
|
lines = int(sys.argv[2]) if len(sys.argv) > 2 else 20
|
||||||
|
manager.errors(lines)
|
||||||
|
else:
|
||||||
|
print(f"❌ Неизвестная команда: {command}")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
Reference in New Issue
Block a user