From 39c99c416578a64bc88f7c5a8394bc990b88402b Mon Sep 17 00:00:00 2001 From: kolo Date: Sat, 3 Jan 2026 16:38:00 +0300 Subject: [PATCH] Initial commit --- src/trudex/application/__main__.py | 14 ++++++++++-- src/trudex/infrastructure/di.py | 22 ++++++++++++++++++- src/trudex/infrastructure/scheduling/tasks.py | 17 ++++++++++++++ 3 files changed, 50 insertions(+), 3 deletions(-) create mode 100644 src/trudex/infrastructure/scheduling/tasks.py diff --git a/src/trudex/application/__main__.py b/src/trudex/application/__main__.py index 8ed7b1f..62674a8 100644 --- a/src/trudex/application/__main__.py +++ b/src/trudex/application/__main__.py @@ -5,6 +5,7 @@ from aiogram import Bot, Dispatcher from aiogram.client.default import DefaultBotProperties from aiogram.enums import ParseMode from aiogram_dialog import setup_dialogs +from apscheduler.schedulers.asyncio import AsyncIOScheduler from dishka import make_async_container from dishka.integrations.aiogram import setup_dishka @@ -38,7 +39,7 @@ from trudex.application.bot.user_dialogs.main_menu import user_menu_dialog from trudex.application.bot.user_dialogs.registration import \ registration_dialog from trudex.infrastructure.database.repo.user import UserRepository -from trudex.infrastructure.di import DatabaseProvider +from trudex.infrastructure.di import DatabaseProvider, SchedulerProvider from trudex.infrastructure.utils.bot_commands import setup_bot_commands from trudex.infrastructure.utils.config import Config @@ -78,7 +79,11 @@ async def main() -> None: router.message.middleware(RejectNotAdminMiddleware()) router.message.middleware(RejectNotCreatorMiddleware()) - container = make_async_container(DatabaseProvider(), context={Bot: bot, Config: config}) + container = make_async_container( + DatabaseProvider(), + SchedulerProvider(), + context={Bot: bot, Config: config} + ) setup_dialogs(dp) setup_dishka(container, dp, auto_inject=True) @@ -88,13 +93,18 @@ async def main() -> None: user_repo = await request_container.get(UserRepository) await setup_bot_commands(bot, config, user_repo) + scheduler = await container.get(AsyncIOScheduler) + scheduler.start() + await bot.delete_webhook(drop_pending_updates=True) logging.info("Бот запущен") + logging.info("Планировщик задач запущен") try: await dp.start_polling(bot) finally: + scheduler.shutdown() await bot.session.close() diff --git a/src/trudex/infrastructure/di.py b/src/trudex/infrastructure/di.py index a9c3e20..fa4b406 100644 --- a/src/trudex/infrastructure/di.py +++ b/src/trudex/infrastructure/di.py @@ -1,6 +1,8 @@ from collections.abc import AsyncIterable +import logging -from dishka import Provider, Scope, provide +from apscheduler.schedulers.asyncio import AsyncIOScheduler +from dishka import AsyncContainer, Provider, Scope, provide from sqlalchemy.ext.asyncio import AsyncSession, async_sessionmaker from trudex.infrastructure.database.config import new_session_maker @@ -15,6 +17,7 @@ from trudex.infrastructure.database.repo.test import TestRepository from trudex.infrastructure.database.repo.test_attempt import \ TestAttemptRepository from trudex.infrastructure.database.repo.user import UserRepository +from trudex.infrastructure.scheduling.tasks import deactivate_expired_tests from trudex.infrastructure.utils.config import Config @@ -70,3 +73,20 @@ class DatabaseProvider(Provider): @provide(scope=Scope.REQUEST) def get_test_attempt_repository(self, session: AsyncSession) -> TestAttemptRepository: return TestAttemptRepository(session) + + +class SchedulerProvider(Provider): + @provide(scope = Scope.APP) + def get_scheduler(self, container: AsyncContainer) -> AsyncIOScheduler: + logging.getLogger('apscheduler').setLevel(logging.WARNING) + scheduler = AsyncIOScheduler() + + scheduler.add_job( + deactivate_expired_tests, + 'interval', + minutes=5, + args=[container], + id='deactivate_expired_tests', + ) + + return scheduler diff --git a/src/trudex/infrastructure/scheduling/tasks.py b/src/trudex/infrastructure/scheduling/tasks.py new file mode 100644 index 0000000..baefebf --- /dev/null +++ b/src/trudex/infrastructure/scheduling/tasks.py @@ -0,0 +1,17 @@ +from datetime import datetime + +from dishka import AsyncContainer + +from trudex.infrastructure.database.dao.test import TestDAO +from trudex.infrastructure.database.models import Test + + +async def deactivate_expired_tests(container: AsyncContainer): + async with container() as request_container: + test_dao = await request_container.get(TestDAO) + + tests = await test_dao.get_all() + + for test in tests: + if test.expires_at and test.expires_at < datetime.utcnow() and test.is_active: + await test_dao.update(test.id, is_active=False)