fix payment
This commit is contained in:
+42
-50
@@ -1,10 +1,9 @@
|
||||
"""
|
||||
Нагрузочный тест: N параллельных браузеров на X секунд.
|
||||
Нагрузочный тест: N визитов через BrowserPool.
|
||||
|
||||
Использование:
|
||||
python load_test.py --n 5
|
||||
python load_test.py --n 10 --url https://example.com --time 15
|
||||
python load_test.py --n 10 --parallel 3 # не более 3 одновременных запусков
|
||||
python load_test.py --n 10 --url https://example.com --time 15 --workers 3
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
@@ -22,6 +21,7 @@ import psutil
|
||||
from core.logger import setup_logger
|
||||
from managers.proxy_manager import ProxyManager
|
||||
from services.browser_service import BrowserService
|
||||
from services.browser_pool import BrowserPool
|
||||
|
||||
logger = setup_logger(name="load_test", log_level="INFO", log_file="logs/load_test.log")
|
||||
|
||||
@@ -38,46 +38,39 @@ class BrowserResult:
|
||||
success: bool
|
||||
duration: float
|
||||
error: Optional[str] = None
|
||||
final_url: Optional[str] = None
|
||||
|
||||
|
||||
async def run_one_browser(
|
||||
async def submit_visit(
|
||||
index: int,
|
||||
browser_service: BrowserService,
|
||||
pool: BrowserPool,
|
||||
url: str,
|
||||
visit_time: int,
|
||||
results: List[BrowserResult],
|
||||
launch_sem: asyncio.Semaphore,
|
||||
) -> None:
|
||||
# Семафор ограничивает сколько браузеров стартует одновременно.
|
||||
# Когда браузер поднялся (AsyncCamoufox.__aenter__ завершён), семафор освобождается
|
||||
# и следующий браузер может начать запуск. Так избегаем race на ресурсы ОС.
|
||||
async with launch_sem:
|
||||
t0 = time.perf_counter()
|
||||
try:
|
||||
result = await browser_service.visit_page(url, reading_time=visit_time)
|
||||
duration = time.perf_counter() - t0
|
||||
results.append(BrowserResult(
|
||||
index=index,
|
||||
success=result.success,
|
||||
duration=duration,
|
||||
error=result.error,
|
||||
final_url=result.final_url,
|
||||
))
|
||||
status = "OK" if result.success else f"FAIL: {result.error}"
|
||||
print(f" [Browser {index:>2}] {status} — {duration:.1f}s | RAM: {_mem_mb():.0f} MB")
|
||||
except Exception as e:
|
||||
duration = time.perf_counter() - t0
|
||||
results.append(BrowserResult(index=index, success=False, duration=duration, error=str(e)))
|
||||
print(f" [Browser {index:>2}] EXCEPTION: {e} — {duration:.1f}s")
|
||||
t0 = time.perf_counter()
|
||||
try:
|
||||
result = await pool.visit_page(url, reading_time=visit_time)
|
||||
duration = time.perf_counter() - t0
|
||||
results.append(BrowserResult(
|
||||
index=index,
|
||||
success=result.success,
|
||||
duration=duration,
|
||||
error=result.error,
|
||||
))
|
||||
status = "OK" if result.success else f"FAIL: {result.error}"
|
||||
print(f" [#{index:>2}] {status} — {duration:.1f}s | RAM: {_mem_mb():.0f} MB")
|
||||
except Exception as e:
|
||||
duration = time.perf_counter() - t0
|
||||
results.append(BrowserResult(index=index, success=False, duration=duration, error=str(e)))
|
||||
print(f" [#{index:>2}] EXCEPTION: {e} — {duration:.1f}s")
|
||||
|
||||
|
||||
async def run_load_test(n: int, url: str, visit_time: int, parallel: int) -> None:
|
||||
async def run_load_test(n: int, url: str, visit_time: int, workers: int) -> None:
|
||||
print(f"\n{'='*60}")
|
||||
print(f" Нагрузочный тест")
|
||||
print(f" Браузеров: {n} | Одновременный запуск: {parallel} | URL: {url} | Время: {visit_time}s")
|
||||
print(f" Визитов: {n} | Воркеров: {workers} | Время: {visit_time}s")
|
||||
print(f" URL: {url}")
|
||||
|
||||
# Инфо о системе
|
||||
mem = psutil.virtual_memory()
|
||||
print(f" RAM всего: {mem.total / (1024**3):.1f} GB | Свободно: {mem.available / (1024**3):.1f} GB")
|
||||
print(f" CPU ядер: {psutil.cpu_count()}")
|
||||
@@ -87,24 +80,23 @@ async def run_load_test(n: int, url: str, visit_time: int, parallel: int) -> Non
|
||||
await proxy_manager.detect_types()
|
||||
|
||||
proxy_count = proxy_manager.count
|
||||
if proxy_count < n:
|
||||
print(f" ВНИМАНИЕ: прокси {proxy_count} < браузеров {n}.")
|
||||
print(f" Некоторые браузеры могут не получить прокси.\n")
|
||||
if proxy_count < workers:
|
||||
print(f" ВНИМАНИЕ: прокси {proxy_count} < воркеров {workers}.")
|
||||
print(f" Часть воркеров может ждать свободный прокси.\n")
|
||||
|
||||
browser_service = BrowserService(proxy_manager)
|
||||
results: List[BrowserResult] = []
|
||||
pool = BrowserPool(size=workers, browser_service=browser_service)
|
||||
await pool.start()
|
||||
|
||||
results: List[BrowserResult] = []
|
||||
ram_before = _mem_mb()
|
||||
print(f" RAM до старта: {ram_before:.0f} MB")
|
||||
print(f"\n Запускаем {n} браузеров (волнами по {parallel})...\n")
|
||||
print(f"\n Отправляем {n} визитов в пул ({workers} воркеров)...\n")
|
||||
|
||||
launch_sem = asyncio.Semaphore(parallel)
|
||||
wall_start = time.perf_counter()
|
||||
|
||||
tasks = [
|
||||
asyncio.create_task(
|
||||
run_one_browser(i + 1, browser_service, url, visit_time, results, launch_sem)
|
||||
)
|
||||
asyncio.create_task(submit_visit(i + 1, pool, url, visit_time, results))
|
||||
for i in range(n)
|
||||
]
|
||||
await asyncio.gather(*tasks, return_exceptions=True)
|
||||
@@ -112,9 +104,9 @@ async def run_load_test(n: int, url: str, visit_time: int, parallel: int) -> Non
|
||||
wall_elapsed = time.perf_counter() - wall_start
|
||||
ram_after = _mem_mb()
|
||||
|
||||
await pool.stop()
|
||||
await browser_service.cleanup()
|
||||
|
||||
# --- Итоги ---
|
||||
ok = sum(1 for r in results if r.success)
|
||||
fail = len(results) - ok
|
||||
avg_dur = sum(r.duration for r in results) / len(results) if results else 0
|
||||
@@ -124,34 +116,34 @@ async def run_load_test(n: int, url: str, visit_time: int, parallel: int) -> Non
|
||||
print(f"\n{'='*60}")
|
||||
print(f" ИТОГИ")
|
||||
print(f"{'='*60}")
|
||||
print(f" Всего браузеров : {n}")
|
||||
print(f" Визитов всего : {n}")
|
||||
print(f" Успешно : {ok}")
|
||||
print(f" Ошибки : {fail}")
|
||||
print(f" Общее время : {wall_elapsed:.1f}s")
|
||||
print(f" Время посещения : avg={avg_dur:.1f}s min={min_dur:.1f}s max={max_dur:.1f}s")
|
||||
print(f" Время визита : avg={avg_dur:.1f}s min={min_dur:.1f}s max={max_dur:.1f}s")
|
||||
print(f" RAM до/после : {ram_before:.0f} MB → {ram_after:.0f} MB (Δ {ram_after - ram_before:+.0f} MB)")
|
||||
print(f" RAM на браузер : ~{(ram_after - ram_before) / n if n else 0:.0f} MB")
|
||||
print(f" RAM на воркер : ~{(ram_after - ram_before) / workers if workers else 0:.0f} MB")
|
||||
|
||||
if fail:
|
||||
print(f"\n Ошибки:")
|
||||
for r in results:
|
||||
if not r.success:
|
||||
print(f" Browser {r.index}: {r.error}")
|
||||
print(f" #{r.index}: {r.error}")
|
||||
|
||||
print(f"{'='*60}\n")
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description="Load test: N параллельных браузеров")
|
||||
parser.add_argument("--n", type=int, default=3, help="Всего браузеров (по умолчанию: 3)")
|
||||
parser.add_argument("--parallel", type=int, default=2, help="Макс. одновременных запусков (по умолчанию: 2)")
|
||||
parser = argparse.ArgumentParser(description="Load test через BrowserPool")
|
||||
parser.add_argument("--n", type=int, default=5, help="Число визитов (по умолчанию: 5)")
|
||||
parser.add_argument("--workers", type=int, default=2, help="Число параллельных воркеров/браузеров (по умолчанию: 2)")
|
||||
parser.add_argument("--url", type=str, default="https://httpbin.org/headers", help="URL для посещения")
|
||||
parser.add_argument("--time", type=int, default=10, dest="visit_time", help="Время посещения в секундах (по умолчанию: 10)")
|
||||
args = parser.parse_args()
|
||||
|
||||
parallel = min(args.parallel, args.n)
|
||||
workers = min(args.workers, args.n)
|
||||
try:
|
||||
asyncio.run(run_load_test(args.n, args.url, args.visit_time, parallel))
|
||||
asyncio.run(run_load_test(args.n, args.url, args.visit_time, workers))
|
||||
except KeyboardInterrupt:
|
||||
print("\nПрервано.")
|
||||
|
||||
|
||||
Reference in New Issue
Block a user