diff --git a/buildfiles/SchedulerDockerfile b/buildfiles/SchedulerDockerfile new file mode 100644 index 0000000..6b906dc --- /dev/null +++ b/buildfiles/SchedulerDockerfile @@ -0,0 +1,29 @@ +FROM python:3.12-slim as python-base + +ENV POETRY_VERSION=1.7.1 \ + POETRY_HOME=/opt/poetry \ + POETRY_VENV=/opt/poetry-venv \ + POETRY_CACHE_DIR=/opt/.cache + +FROM python-base as poetry-base + +RUN python3 -m venv $POETRY_VENV \ + && $POETRY_VENV/bin/pip install -U pip setuptools \ + && $POETRY_VENV/bin/pip install poetry==${POETRY_VERSION} + +FROM python-base as app + +RUN apt update && apt install -y build-essential + +COPY --from=poetry-base ${POETRY_VENV} ${POETRY_VENV} +ENV PATH="${PATH}:${POETRY_VENV}/bin" + +WORKDIR /app +COPY ../poetry.lock pyproject.toml ./ + +RUN poetry check && \ + poetry install --no-interaction --no-cache --no-root + +COPY .. . + +CMD poetry run arq fanfan.infrastructure.scheduler.WorkerSettings diff --git a/docker-compose.yml b/docker-compose.yml index a12f4f3..ada86d2 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -17,6 +17,7 @@ services: depends_on: - db - redis + - scheduler db: container_name: 'fanfan-db' build: @@ -41,6 +42,17 @@ services: - redis-data:/data ports: - "6379:6379" + scheduler: + container_name: 'fanfan-scheduler' + build: + context: . + dockerfile: buildfiles/SchedulerDockerfile + env_file: + - .env + restart: unless-stopped + stop_signal: SIGINT + depends_on: + - redis volumes: db-data: diff --git a/fanfan/infrastructure/scheduler.py b/fanfan/infrastructure/scheduler.py index fadeab9..f672e09 100644 --- a/fanfan/infrastructure/scheduler.py +++ b/fanfan/infrastructure/scheduler.py @@ -2,10 +2,11 @@ from aiogram import Bot from aiogram.exceptions import TelegramBadRequest, TelegramRetryAfter -from arq import ArqRedis, Retry, Worker +from arq import Retry from fanfan.application.dto.common import UserNotification from fanfan.common.factory import create_bot +from fanfan.config import conf from fanfan.presentation.tgbot.dialogs.widgets import DELETE_BUTTON @@ -35,10 +36,8 @@ async def send_notification(ctx: dict, notification: UserNotification): raise Retry(defer=e.retry_after) -def create_worker(pool: ArqRedis) -> Worker: - return Worker( - redis_pool=pool, - on_startup=startup, - on_shutdown=shutdown, - functions=[send_notification], - ) +class WorkerSettings: + functions = [send_notification] + on_startup = startup + on_shutdown = shutdown + redis_settings = conf.redis.get_pool_settings() diff --git a/fanfan/presentation/tgbot/__main__.py b/fanfan/presentation/tgbot/__main__.py index 159be67..9115526 100644 --- a/fanfan/presentation/tgbot/__main__.py +++ b/fanfan/presentation/tgbot/__main__.py @@ -6,7 +6,6 @@ import sentry_sdk import uvicorn from aiogram.fsm.storage.memory import SimpleEventIsolation -from arq import create_pool from fastapi import FastAPI from sentry_sdk.integrations.asyncio import AsyncioIntegration from sentry_sdk.integrations.redis import RedisIntegration @@ -22,7 +21,6 @@ from fanfan.infrastructure.db.main import create_async_engine, create_session_pool from fanfan.infrastructure.db.uow import UnitOfWork from fanfan.infrastructure.redis import create_redis_client, create_redis_storage -from fanfan.infrastructure.scheduler import create_worker from fanfan.presentation.sqladmin.admin import setup_admin from fanfan.presentation.tgbot.dispatcher import create_dispatcher from fanfan.presentation.tgbot.utils.webapp import webapp_router @@ -82,11 +80,7 @@ async def lifespan(app: FastAPI): await bot.delete_webhook(drop_pending_updates=True) asyncio.create_task(dp.start_polling(bot)) logging.info("Running in polling mode") - worker = create_worker(await create_pool(conf.redis.get_pool_settings())) - asyncio.create_task(worker.async_run()) yield - logging.info("Stopping schedule worker...") - await worker.close() logging.info("Closing bot session...") await bot.session.close() logging.info("Disposing db engine...")