fix delete old state
This commit is contained in:
@@ -2248,6 +2248,8 @@ class BotInterface:
|
|||||||
params.successful_visits += 1
|
params.successful_visits += 1
|
||||||
await self.balance_storage.deduct(params.user_id, 1)
|
await self.balance_storage.deduct(params.user_id, 1)
|
||||||
logger.info(f"✅ Visit {params.successful_visits}/{max_v}: {params.url[:40]}")
|
logger.info(f"✅ Visit {params.successful_visits}/{max_v}: {params.url[:40]}")
|
||||||
|
if self.storage:
|
||||||
|
await self.storage.save_task(task_id, params)
|
||||||
else:
|
else:
|
||||||
logger.warning(f"❌ Visit failed ({params.total_visits}): {result.error or 'unknown'}")
|
logger.warning(f"❌ Visit failed ({params.total_visits}): {result.error or 'unknown'}")
|
||||||
except asyncio.CancelledError:
|
except asyncio.CancelledError:
|
||||||
|
|||||||
@@ -42,6 +42,7 @@ class BotApplication:
|
|||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.bot: Bot = None
|
self.bot: Bot = None
|
||||||
self.dispatcher: Dispatcher = None
|
self.dispatcher: Dispatcher = None
|
||||||
|
self._initialized = False # True только после успешного _restore_tasks
|
||||||
|
|
||||||
self.background_tasks = BackgroundTaskManager()
|
self.background_tasks = BackgroundTaskManager()
|
||||||
self.browser_service = BrowserService()
|
self.browser_service = BrowserService()
|
||||||
@@ -101,8 +102,24 @@ class BotApplication:
|
|||||||
# Восстанавливаем задачи
|
# Восстанавливаем задачи
|
||||||
await self._restore_tasks()
|
await self._restore_tasks()
|
||||||
|
|
||||||
|
self._initialized = True
|
||||||
|
|
||||||
|
# Периодическое сохранение на случай аварийного завершения
|
||||||
|
asyncio.create_task(self._autosave_loop(), name="autosave")
|
||||||
|
|
||||||
logger.info("Bot initialized!")
|
logger.info("Bot initialized!")
|
||||||
|
|
||||||
|
async def _autosave_loop(self):
|
||||||
|
"""Сохраняет состояние задач каждые 60 секунд."""
|
||||||
|
while True:
|
||||||
|
await asyncio.sleep(60)
|
||||||
|
try:
|
||||||
|
tasks = dict(self.interface.task_manager._tasks)
|
||||||
|
await self.storage.save_tasks(tasks)
|
||||||
|
logger.debug(f"Autosaved {len(tasks)} tasks")
|
||||||
|
except Exception as e:
|
||||||
|
logger.warning(f"Autosave failed: {e}")
|
||||||
|
|
||||||
async def _restore_tasks(self):
|
async def _restore_tasks(self):
|
||||||
"""Восстанавливает задачи после перезапуска."""
|
"""Восстанавливает задачи после перезапуска."""
|
||||||
saved_tasks = await self.storage.load_tasks()
|
saved_tasks = await self.storage.load_tasks()
|
||||||
@@ -174,9 +191,11 @@ class BotApplication:
|
|||||||
"""Остановка с сохранением."""
|
"""Остановка с сохранением."""
|
||||||
logger.info("Shutting down...")
|
logger.info("Shutting down...")
|
||||||
|
|
||||||
# Сохраняем задачи
|
# Сохраняем только если инициализация прошла успешно —
|
||||||
tasks = self.interface.task_manager._tasks
|
# иначе task_manager пустой и мы затрём уже сохранённые задачи
|
||||||
await self.storage.save_tasks(tasks)
|
if self._initialized:
|
||||||
|
tasks = self.interface.task_manager._tasks
|
||||||
|
await self.storage.save_tasks(tasks)
|
||||||
|
|
||||||
await self.background_tasks.cancel_all()
|
await self.background_tasks.cancel_all()
|
||||||
await self.browser_pool.stop()
|
await self.browser_pool.stop()
|
||||||
|
|||||||
+15
-7
@@ -135,15 +135,23 @@ class TaskStorage:
|
|||||||
return {}
|
return {}
|
||||||
|
|
||||||
async def save_task(self, task_id: str, params: TaskParams) -> None:
|
async def save_task(self, task_id: str, params: TaskParams) -> None:
|
||||||
tasks = await self.load_tasks()
|
async with self._lock:
|
||||||
tasks[task_id] = params
|
try:
|
||||||
await self.save_tasks(tasks)
|
data = await asyncio.to_thread(self._load_sync)
|
||||||
|
data[task_id] = self._params_to_dict(params)
|
||||||
|
await asyncio.to_thread(self._save_sync, data)
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"save_task error: {e}")
|
||||||
|
|
||||||
async def delete_task(self, task_id: str) -> None:
|
async def delete_task(self, task_id: str) -> None:
|
||||||
tasks = await self.load_tasks()
|
async with self._lock:
|
||||||
if task_id in tasks:
|
try:
|
||||||
del tasks[task_id]
|
data = await asyncio.to_thread(self._load_sync)
|
||||||
await self.save_tasks(tasks)
|
if task_id in data:
|
||||||
|
del data[task_id]
|
||||||
|
await asyncio.to_thread(self._save_sync, data)
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"delete_task error: {e}")
|
||||||
|
|
||||||
|
|
||||||
class ChatStorage:
|
class ChatStorage:
|
||||||
|
|||||||
@@ -165,6 +165,9 @@ class BrowserService:
|
|||||||
if not settings.STICKY_PROXY_HOST:
|
if not settings.STICKY_PROXY_HOST:
|
||||||
return VisitResult(url=url, success=False, error="No proxy configured")
|
return VisitResult(url=url, success=False, error="No proxy configured")
|
||||||
|
|
||||||
|
# Максимальное время одной попытки: запуск браузера + загрузка страницы + чтение + буфер
|
||||||
|
attempt_timeout = reading_time + 150
|
||||||
|
|
||||||
for attempt in range(3):
|
for attempt in range(3):
|
||||||
try:
|
try:
|
||||||
proxy_config, proxy_url, proxy_info = _make_sticky_proxy_config()
|
proxy_config, proxy_url, proxy_info = _make_sticky_proxy_config()
|
||||||
@@ -185,8 +188,11 @@ class BrowserService:
|
|||||||
if proxy_locale:
|
if proxy_locale:
|
||||||
camoufox_kwargs["locale"] = proxy_locale
|
camoufox_kwargs["locale"] = proxy_locale
|
||||||
|
|
||||||
async with AsyncCamoufox(**camoufox_kwargs) as browser:
|
async def _run_browser():
|
||||||
result = await self._browse_page(browser, url, proxy_info, reading_time)
|
async with AsyncCamoufox(**camoufox_kwargs) as browser:
|
||||||
|
return await self._browse_page(browser, url, proxy_info, reading_time)
|
||||||
|
|
||||||
|
result = await asyncio.wait_for(_run_browser(), timeout=attempt_timeout)
|
||||||
|
|
||||||
is_proxy_dead = result.error and any(
|
is_proxy_dead = result.error and any(
|
||||||
k in result.error for k in ("502", "Bad Gateway", "NS_ERROR_PROXY")
|
k in result.error for k in ("502", "Bad Gateway", "NS_ERROR_PROXY")
|
||||||
@@ -204,6 +210,9 @@ class BrowserService:
|
|||||||
self._proxy_fail_streak = 0
|
self._proxy_fail_streak = 0
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
except asyncio.TimeoutError:
|
||||||
|
logger.warning(f"Visit attempt {attempt + 1} timed out after {attempt_timeout}s, retrying")
|
||||||
|
|
||||||
except (ValueError, InvalidIP, InvalidProxy) as e:
|
except (ValueError, InvalidIP, InvalidProxy) as e:
|
||||||
logger.warning(f"Visit attempt {attempt + 1} proxy error, retrying: {e}")
|
logger.warning(f"Visit attempt {attempt + 1} proxy error, retrying: {e}")
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user