"""Background worker that e-mails CDEK waybill PDFs.""" import asyncio import signal import httpx import structlog from app.adapters.delivery_providers.cdek.auth import CDEKAuthClient from app.adapters.delivery_providers.cdek.client import CDEKClient from app.adapters.email import SMTPEmailSender from app.adapters.postgres.engine import ( create_postgres_engine, create_postgres_session_factory, ) from app.config import Settings, get_settings from app.repositories.order import OrderRepository from app.runtime.logging import configure_logging from app.services.waybill_email_sender import WaybillEmailSenderService logger = structlog.get_logger(__name__) async def _run(settings: Settings, stop_event: asyncio.Event) -> None: http_client = httpx.AsyncClient(timeout=settings.adapter.cdek_timeout_seconds) auth_client = CDEKAuthClient( http_client=http_client, base_url=settings.adapter.cdek_base_url, client_id=settings.adapter.cdek_client_id, client_secret=settings.adapter.cdek_client_secret, timeout_seconds=settings.adapter.cdek_timeout_seconds, ) cdek_client = CDEKClient( http_client=http_client, auth_client=auth_client, base_url=settings.adapter.cdek_base_url, timeout_seconds=settings.adapter.cdek_timeout_seconds, retry_attempts=settings.adapter.cdek_retry_attempts, retry_backoff_seconds=settings.adapter.cdek_retry_backoff_seconds, ) email_sender = SMTPEmailSender( smtp_host=settings.email.smtp_host, smtp_port=settings.email.smtp_port, username=settings.email.username, password=settings.email.password, from_address=settings.email.from_address, use_tls=settings.email.use_tls, timeout_seconds=settings.email.timeout_seconds, ) engine = create_postgres_engine(settings.postgres) session_factory = create_postgres_session_factory(engine) repository = OrderRepository(session_factory=session_factory) service = WaybillEmailSenderService( order_repository=repository, waybill_downloader=cdek_client, email_sender=email_sender, batch_size=settings.waybill_email_sender.batch_size, ) logger.info( "waybill_email_sender_started", interval_seconds=settings.waybill_email_sender.interval_seconds, batch_size=settings.waybill_email_sender.batch_size, ) try: await service.run_forever( interval_seconds=settings.waybill_email_sender.interval_seconds, stop_event=stop_event, ) finally: await http_client.aclose() await engine.dispose() logger.info("waybill_email_sender_stopped") async def main() -> None: configure_logging() settings = get_settings() stop_event = asyncio.Event() loop = asyncio.get_running_loop() for sig in (signal.SIGTERM, signal.SIGINT): try: loop.add_signal_handler(sig, stop_event.set) except NotImplementedError: pass await _run(settings, stop_event) if __name__ == "__main__": asyncio.run(main())