Добавлена проверка перед скачиванием, что файл бэкапа уже полностью

создан
This commit is contained in:
VolandSZ
2026-03-15 19:34:44 +03:00
parent d06615b0b3
commit d735cc1932
2 changed files with 64 additions and 44 deletions

108
main.py
View File

@ -3,7 +3,7 @@ import re
import time
# from datetime import datetime
from dataclasses import dataclass, field
from dataclasses import dataclass
# from pathlib import Path
from playwright.sync_api import (
@ -234,7 +234,7 @@ class BackupManager:
backup_data: bool = False,
backup_mysql: bool = True,
wait_for_completion: bool = True,
poll_interval: int = 30,
poll_interval: int = 60,
max_wait: int = 600,
):
"""
@ -323,7 +323,7 @@ class BackupManager:
) -> bool:
"""Ожидание завершения создания бэкапа"""
print(f"\n[*] Ожидание завершения (макс. {max_wait} сек)...")
print(f" Ожидаем {expected_new} новых файлов")
print(f" Ожидаем {expected_new} новых готовых файлов")
start_time = time.time()
attempt = 0
@ -340,52 +340,73 @@ class BackupManager:
# Обновляем список через ссылку на странице
self._refresh_backup_list()
files_now = self.parse_backup_table()
count_now = len(files_now)
new_count = count_now - count_before
print(f"файлов: {count_now} (новых: {new_count})")
# Считаем только ГОТОВЫЕ файлы (размер вида "12345 KB" без "формируется")
ready_files = [f for f in files_now if self._is_file_ready(f)]
ready_count = len(ready_files)
new_ready = ready_count - count_before
if new_count >= expected_new:
print(f"\n[OK] Бэкап создан! Новых файлов: {new_count}")
# Считаем файлы в процессе создания
in_progress = [f for f in files_now if not self._is_file_ready(f)]
print(
f"готовых: {ready_count} (новых: {new_ready}), в процессе: {len(in_progress)}"
)
if in_progress:
for f in in_progress:
print(f"{f.name}{f.size}")
if new_ready >= expected_new:
print(f"\n[OK] Бэкап создан! Новых готовых файлов: {new_ready}")
return True
# Проверяем статус задания
status = self._check_task_status()
if status:
for s in status:
print(f" Задание: {s}")
# status = self._check_task_status()
# if status:
# for s in status:
# print(f" Задание: {s}")
print(f" Следующая проверка через {poll_interval} сек...")
time.sleep(poll_interval)
def _check_task_status(self) -> list[str]:
"""Проверяет статус заданий в таблице Schedule/Operation"""
statuses = self.page.evaluate("""() => {
const tables = document.querySelectorAll('table');
const results = [];
def _is_file_ready(self, backup_file: BackupFile) -> bool:
"""Проверяет что файл готов (не в процессе создания)"""
size = backup_file.size.lower()
# Готовый файл: "1033513 KB"
# В процессе: "файл формируется, 50048 KB"
if "формируется" in size or "создаётся" in size or "progress" in size:
return False
return True
for (const table of tables) {
const headers = table.querySelectorAll('th');
const headerTexts = Array.from(headers).map(h => h.innerText.trim());
# def _check_task_status(self) -> list[str]:
# """Проверяет статус заданий в таблице Schedule/Operation"""
# statuses = self.page.evaluate("""() => {
# const tables = document.querySelectorAll('table');
# const results = [];
if (headerTexts.some(h => h.includes('Schedule') || h.includes('Operation'))) {
const rows = table.querySelectorAll('tr');
for (const row of rows) {
const cells = row.querySelectorAll('td');
if (cells.length >= 3) {
const schedule = cells[0]?.innerText?.trim() || '';
const server = cells[1]?.innerText?.trim() || '';
const operation = cells[2]?.innerText?.trim() || '';
if (schedule || operation) {
results.push(`${schedule} | ${server} | ${operation}`);
}
}
}
}
}
return results;
}""")
return statuses
# for (const table of tables) {
# const headers = table.querySelectorAll('th');
# const headerTexts = Array.from(headers).map(h => h.innerText.trim());
# if (headerTexts.some(h => h.includes('Schedule') || h.includes('Operation'))) {
# const rows = table.querySelectorAll('tr');
# for (const row of rows) {
# const cells = row.querySelectorAll('td');
# if (cells.length >= 3) {
# const schedule = cells[0]?.innerText?.trim() || '';
# const server = cells[1]?.innerText?.trim() || '';
# const operation = cells[2]?.innerText?.trim() || '';
# if (schedule || operation) {
# results.push(`${schedule} | ${server} | ${operation}`);
# }
# }
# }
# }
# }
# return results;
# }""")
# return statuses
def create_backup_mysql_only(self, wait: bool = True):
"""Создать только бэкап базы данных"""
@ -647,16 +668,15 @@ class BackupManager:
# print("ПРОПУЩЕНО (удаление закомментировано)")
print(f"\n[OK] Готово")
print("\n[OK] Готово")
# === ИСПОЛЬЗОВАНИЕ ===
if __name__ == "__main__":
mgr = BackupManager(
username="minzdravmo",
password="KB3ZS7*sv6j4zYr@bPdeFWQN38rbtQv",
# backup_folder=Path("F:/test_folder/MyReports"),
username="rav",
password="KB3e8rbtQv",
account_id="564622",
)
@ -678,9 +698,9 @@ if __name__ == "__main__":
)
# 3. Показать, что удаляем и удалить
mgr.print_deletion_plan(delete_count=1, year=2026)
# mgr.print_deletion_plan(delete_count=1, year=2026)
mgr.delete_old_backups(delete_count=1, year=2026)
# mgr.delete_old_backups(delete_count=1, year=2026)
# Скачать только последний бэкап (без создания нового)
# mgr.download_latest(save_dir="./backups")

BIN
requirements.txt Normal file

Binary file not shown.