init auth and main function

This commit is contained in:
Yuriy Yuriev
2026-05-14 16:15:58 +07:00
commit 27c53e897e
47 changed files with 5750 additions and 0 deletions
+409
View File
@@ -0,0 +1,409 @@
"""
Точный тест потребления памяти с отслеживанием ВСЕХ процессов.
Измеряет память Python + браузерных процессов отдельно.
Запуск: python -u test_memory_processes.py
"""
import asyncio
import sys
import os
import time
import traceback
from datetime import datetime
import gc
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
def print_flush(*args, **kwargs):
print(*args, **kwargs, flush=True)
import psutil
from config.settings import settings
from managers.proxy_manager import ProxyManager
from services.browser_service import BrowserService
print_flush("=" * 70)
print_flush("🧠 ТОЧНЫЙ ТЕСТ ПАМЯТИ (ВСЕ ПРОЦЕССЫ)")
print_flush("=" * 70)
print_flush(f"Время: {datetime.now().strftime('%H:%M:%S')}")
print_flush()
def get_process_tree_memory() -> dict:
"""
Получает память текущего процесса и всех его дочерних процессов.
Возвращает детальную информацию.
"""
current = psutil.Process()
total_rss = current.memory_info().rss
children = []
try:
for child in current.children(recursive=True):
try:
child_rss = child.memory_info().rss
children.append({
"pid": child.pid,
"name": child.name()[:50],
"rss_mb": child_rss / (1024 * 1024),
"status": child.status()
})
total_rss += child_rss
except (psutil.NoSuchProcess, psutil.AccessDenied):
pass
except (psutil.NoSuchProcess, psutil.AccessDenied):
pass
return {
"python_rss_mb": current.memory_info().rss / (1024 * 1024),
"children_count": len(children),
"children_rss_mb": sum(c["rss_mb"] for c in children),
"total_rss_mb": total_rss / (1024 * 1024),
"children": children
}
def get_browser_processes() -> list:
"""
Ищет все браузерные процессы (chromium, chrome, firefox).
"""
browser_names = ["chromium", "chrome", "firefox", "camoufox", "playwright"]
browsers = []
for proc in psutil.process_iter(['pid', 'name', 'memory_info']):
try:
name = proc.info['name'].lower() if proc.info['name'] else ""
if any(bn in name for bn in browser_names):
browsers.append({
"pid": proc.info['pid'],
"name": proc.info['name'],
"rss_mb": proc.info['memory_info'].rss / (1024 * 1024)
})
except (psutil.NoSuchProcess, psutil.AccessDenied):
pass
return browsers
def get_system_memory() -> dict:
"""Получает общую информацию о системной памяти."""
mem = psutil.virtual_memory()
swap = psutil.swap_memory()
return {
"total_gb": mem.total / (1024**3),
"available_gb": mem.available / (1024**3),
"used_percent": mem.percent,
"used_gb": mem.used / (1024**3),
"swap_total_gb": swap.total / (1024**3) if swap.total > 0 else 0,
"swap_used_gb": swap.used / (1024**3) if swap.total > 0 else 0,
}
async def monitor_memory_during_operation(duration: int, interval: float = 0.5):
"""
Мониторит память во время операции.
Возвращает макс, мин, среднее и временной ряд.
"""
samples = []
start = time.time()
while time.time() - start < duration:
mem_info = get_process_tree_memory()
system_mem = get_system_memory()
browser_procs = get_browser_processes()
samples.append({
"timestamp": time.time() - start,
"python_mb": mem_info["python_rss_mb"],
"children_mb": mem_info["children_rss_mb"],
"total_mb": mem_info["total_rss_mb"],
"browser_processes": len(browser_procs),
"browser_rss_mb": sum(b["rss_mb"] for b in browser_procs),
"system_used_percent": system_mem["used_percent"],
"children_count": mem_info["children_count"]
})
await asyncio.sleep(interval)
return samples
async def test_single_visit_memory():
"""Тест памяти при одном посещении."""
print_flush("\n" + "=" * 70)
print_flush("🧪 ТЕСТ: ОДИНОЧНОЕ ПОСЕЩЕНИЕ (ПОЛНЫЙ ЦИКЛ)")
print_flush("=" * 70)
# Информация о системе
sys_mem = get_system_memory()
print_flush(f"\n💻 Система:")
print_flush(f" RAM всего: {sys_mem['total_gb']:.1f} GB")
print_flush(f" RAM доступно: {sys_mem['available_gb']:.1f} GB")
print_flush(f" RAM используется: {sys_mem['used_percent']:.1f}%")
print_flush(f" Swap: {sys_mem['swap_total_gb']:.1f} GB")
# Память до
mem_before = get_process_tree_memory()
browsers_before = get_browser_processes()
print_flush(f"\n📊 До запуска:")
print_flush(f" Python процесс: {mem_before['python_rss_mb']:.1f} MB")
print_flush(f" Дочерние процессы: {mem_before['children_count']} шт, "
f"{mem_before['children_rss_mb']:.1f} MB")
print_flush(f" ВСЕГО: {mem_before['total_rss_mb']:.1f} MB")
print_flush(f" Браузерных процессов в системе: {len(browsers_before)}")
if browsers_before:
for b in browsers_before:
print_flush(f" - {b['name']} (PID {b['pid']}): {b['rss_mb']:.1f} MB")
# Запускаем мониторинг
print_flush(f"\n🔄 Запуск браузера и посещение...")
monitor_task = asyncio.create_task(
monitor_memory_during_operation(duration=60, interval=0.3)
)
proxy_manager = ProxyManager()
browser_service = BrowserService(proxy_manager)
url = "https://httpbin.org/headers"
reading_time = 15
print_flush(f" URL: {url}")
print_flush(f" Время чтения: {reading_time}с")
try:
result = await browser_service.visit_page(url, reading_time)
print_flush(f" Статус: {'' if result.success else ''}")
except Exception as e:
print_flush(f" ❌ Ошибка: {e}")
# Ждем завершения мониторинга
await asyncio.sleep(3)
monitor_task.cancel()
try:
samples = await monitor_task
except asyncio.CancelledError:
samples = []
# Память после
await asyncio.sleep(2)
gc.collect()
await asyncio.sleep(1)
mem_after = get_process_tree_memory()
browsers_after = get_browser_processes()
print_flush(f"\n📊 После посещения:")
print_flush(f" Python процесс: {mem_after['python_rss_mb']:.1f} MB")
print_flush(f" Дочерние процессы: {mem_after['children_count']} шт, "
f"{mem_after['children_rss_mb']:.1f} MB")
print_flush(f" ВСЕГО: {mem_after['total_rss_mb']:.1f} MB")
print_flush(f" Браузерных процессов в системе: {len(browsers_after)}")
# Анализ семплов
if samples:
total_samples = [s["total_mb"] for s in samples]
print_flush(f"\n📈 Во время посещения ({len(samples)} замеров):")
print_flush(f" ПИК всего: {max(total_samples):.1f} MB")
print_flush(f" Мин всего: {min(total_samples):.1f} MB")
print_flush(f" Среднее всего: {sum(total_samples)/len(total_samples):.1f} MB")
browser_proc_count = [s["browser_processes"] for s in samples]
if max(browser_proc_count) > 0:
print_flush(f" Макс браузерных процессов: {max(browser_proc_count)}")
# Дельта
delta_total = mem_after["total_rss_mb"] - mem_before["total_rss_mb"]
peak_total = max(s["total_mb"] for s in samples) if samples else mem_after["total_rss_mb"]
peak_delta = peak_total - mem_before["total_rss_mb"]
print_flush(f"\n📊 ИТОГО:")
print_flush(f" Прирост TOTAL (до→после): {delta_total:+.1f} MB")
print_flush(f" ПИКОВЫЙ прирост: {peak_delta:+.1f} MB")
print_flush(f" Системная память: {get_system_memory()['used_percent']:.1f}%")
return {
"mem_before": mem_before,
"mem_after": mem_after,
"samples": samples,
"peak_delta": peak_delta,
"delta_total": delta_total
}
async def test_multiple_sequential(count: int = 5):
"""Тест последовательных посещений с отслеживанием пиков."""
print_flush("\n" + "=" * 70)
print_flush(f"🧪 ТЕСТ: {count} ПОСЛЕДОВАТЕЛЬНЫХ ПОСЕЩЕНИЙ")
print_flush("=" * 70)
proxy_manager = ProxyManager()
browser_service = BrowserService(proxy_manager)
results = []
peak_memory = 0
for i in range(count):
gc.collect()
await asyncio.sleep(0.5)
mem_before = get_process_tree_memory()
system_before = get_system_memory()
url = f"https://httpbin.org/headers?seq={i}"
# Мониторим во время визита
monitor_task = asyncio.create_task(
monitor_memory_during_operation(duration=30, interval=0.3)
)
try:
result = await browser_service.visit_page(url, reading_time=8)
success = result.success
except Exception as e:
success = False
print_flush(f" ❌ Ошибка: {e}")
await asyncio.sleep(1)
monitor_task.cancel()
try:
samples = await monitor_task
except asyncio.CancelledError:
samples = []
mem_after = get_process_tree_memory()
system_after = get_system_memory()
visit_peak = max(s["total_mb"] for s in samples) if samples else mem_after["total_rss_mb"]
if visit_peak > peak_memory:
peak_memory = visit_peak
delta = mem_after["total_rss_mb"] - mem_before["total_rss_mb"]
sys_delta = system_after["used_percent"] - system_before["used_percent"]
results.append({
"visit": i+1,
"mem_before": mem_before["total_rss_mb"],
"mem_after": mem_after["total_rss_mb"],
"peak": visit_peak,
"delta": delta,
"system_delta": sys_delta,
"success": success
})
status = "" if success else ""
print_flush(f" Визит {i+1}: {mem_before['total_rss_mb']:.1f}"
f"{mem_after['total_rss_mb']:.1f} MB (Δ={delta:+.1f} MB, "
f"пик={visit_peak:.1f} MB) {status}")
await asyncio.sleep(random.randint(3, 7))
# Итоги
print_flush(f"\n📊 Итого за {count} посещений:")
print_flush(f" ПИКОВАЯ память за все время: {peak_memory:.1f} MB")
avg_peak = sum(r["peak"] for r in results) / len(results)
print_flush(f" Средний пик: {avg_peak:.1f} MB")
return results, peak_memory
async def main():
"""Главная функция."""
# Тест 1: одиночное посещение
single_result = await test_single_visit_memory()
# Тест 2: последовательные
seq_results, seq_peak = await test_multiple_sequential(5)
# Тест 3: сборка мусора и финальный замер
print_flush("\n" + "=" * 70)
print_flush("🧹 ОЧИСТКА ПОСЛЕ ФИНАЛЬНОГО ТЕСТА")
print_flush("=" * 70)
gc.collect()
await asyncio.sleep(3)
mem_final = get_process_tree_memory()
system_final = get_system_memory()
print_flush(f" Python: {mem_final['python_rss_mb']:.1f} MB")
print_flush(f" Дочерние: {mem_final['children_count']} шт, {mem_final['children_rss_mb']:.1f} MB")
print_flush(f" ВСЕГО: {mem_final['total_rss_mb']:.1f} MB")
print_flush(f" Система: {system_final['used_percent']:.1f}%")
# ИТОГОВЫЕ ОЦЕНКИ
print_flush("\n" + "=" * 70)
print_flush("📊 ИТОГОВЫЕ ОЦЕНКИ ДЛЯ МАСШТАБИРОВАНИЯ")
print_flush("=" * 70)
peak_per_visit = single_result["peak_delta"]
print_flush(f"\n📈 На основе ПИКОВОГО потребления одного браузера:")
print_flush(f" Пиковый прирост: {peak_per_visit:.1f} MB")
# Если пиковый прирост маленький, используем абсолютные значения
if peak_per_visit < 50:
# Браузер уже был в памяти, используем системную дельту
estimate_per_browser = 200 # Консервативная оценка MB на браузер
print_flush(f" ⚠️ Прирост маленький (браузер уже в памяти)")
print_flush(f" Используем консервативную оценку: {estimate_per_browser} MB/браузер")
else:
estimate_per_browser = peak_per_visit
print_flush(f"\n📊 ОЦЕНКИ ДЛЯ РАЗНОГО КОЛИЧЕСТВА ЗАДАЧ:")
print_flush(f" {'Задач':<10} {'RAM (MB)':<15} {'RAM (GB)':<15} {'+50% запас (GB)':<20}")
print_flush(f" {'-'*60}")
for n in [5, 10, 20, 30, 40, 50]:
ram_mb = estimate_per_browser * n
ram_gb = ram_mb / 1024
ram_safe = ram_mb * 1.5 / 1024
print_flush(f" {n:<10} {ram_mb:<15.0f} {ram_gb:<15.2f} {ram_safe:<20.2f}")
# Системные ограничения
sys_mem = get_system_memory()
usable_ram = sys_mem["total_gb"] * 0.8 # 80% от всей RAM
print_flush(f"\n💻 ТЕКУЩАЯ СИСТЕМА:")
print_flush(f" Всего RAM: {sys_mem['total_gb']:.1f} GB")
print_flush(f" Можно использовать (80%): {usable_ram:.1f} GB")
print_flush(f" Максимум задач на этой машине: {int(usable_ram * 1024 / estimate_per_browser)}")
print_flush(f"\n🎯 РЕКОМЕНДАЦИЯ:")
ram_for_50 = estimate_per_browser * 50 * 1.5 / 1024
if ram_for_50 < 4:
print_flush(f" Сервер: 8 GB RAM, 4 vCPU (бюджет)")
elif ram_for_50 < 8:
print_flush(f" Сервер: 16 GB RAM, 8 vCPU")
elif ram_for_50 < 16:
print_flush(f" Сервер: 32 GB RAM, 16 vCPU")
else:
print_flush(f" Сервер: 64 GB RAM, 32 vCPU")
print_flush(f" Диск: 100+ GB SSD")
print_flush(f" Сеть: 100+ Mbps")
print_flush("\n" + "=" * 70)
print_flush("✅ ВСЕ ТЕСТЫ ЗАВЕРШЕНЫ")
print_flush("=" * 70)
if __name__ == "__main__":
import random
try:
asyncio.run(main())
except KeyboardInterrupt:
print_flush("\n⚠️ Прервано")
except Exception as e:
print_flush(f"\n❌ Ошибка: {e}")
traceback.print_exc()
finally:
print_flush("\nНажмите Enter...", end="")
try:
input()
except:
time.sleep(3)