feat(infra): add persistence and SMS adapters
This commit is contained in:
78
src/gapido_auth/infrastructure/worker.py
Normal file
78
src/gapido_auth/infrastructure/worker.py
Normal file
@@ -0,0 +1,78 @@
|
||||
import asyncio
|
||||
import json
|
||||
import logging
|
||||
from typing import Any, cast
|
||||
|
||||
import aio_pika
|
||||
from aio_pika.abc import AbstractIncomingMessage
|
||||
|
||||
from gapido_auth.config import get_settings
|
||||
from gapido_auth.domain.entities import SmsJob
|
||||
from gapido_auth.infrastructure.kavenegar_client import KavenegarSmsClient
|
||||
from gapido_auth.infrastructure.rabbitmq import (
|
||||
SMS_ROUTING_KEY,
|
||||
connect_robust,
|
||||
declare_sms_topology,
|
||||
)
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
MAX_RETRIES = 3
|
||||
|
||||
|
||||
async def handle_message(
|
||||
message: AbstractIncomingMessage,
|
||||
client: KavenegarSmsClient,
|
||||
exchange: Any,
|
||||
dlx: Any,
|
||||
) -> None:
|
||||
async with message.process(ignore_processed=True, requeue=False):
|
||||
payload = json.loads(message.body.decode())
|
||||
job = SmsJob(**payload)
|
||||
retry_count = int(cast(int | str, (message.headers or {}).get("x-retry-count", 0)))
|
||||
|
||||
try:
|
||||
await client.send_otp(job.mobile, job.code, job.template)
|
||||
except Exception:
|
||||
if retry_count >= MAX_RETRIES:
|
||||
logger.exception("SMS job failed permanently for mobile=%s", job.mobile)
|
||||
await dlx.publish(
|
||||
aio_pika.Message(
|
||||
body=message.body,
|
||||
content_type="application/json",
|
||||
headers={"x-retry-count": retry_count},
|
||||
delivery_mode=aio_pika.DeliveryMode.PERSISTENT,
|
||||
),
|
||||
routing_key=SMS_ROUTING_KEY,
|
||||
)
|
||||
return
|
||||
|
||||
logger.warning(
|
||||
"SMS job failed for mobile=%s retry=%s", job.mobile, retry_count + 1, exc_info=True
|
||||
)
|
||||
await exchange.publish(
|
||||
aio_pika.Message(
|
||||
body=message.body,
|
||||
content_type="application/json",
|
||||
headers={"x-retry-count": retry_count + 1},
|
||||
delivery_mode=aio_pika.DeliveryMode.PERSISTENT,
|
||||
),
|
||||
routing_key=SMS_ROUTING_KEY,
|
||||
)
|
||||
|
||||
|
||||
async def main() -> None:
|
||||
logging.basicConfig(level=logging.INFO)
|
||||
settings = get_settings()
|
||||
connection = await connect_robust(settings.rabbitmq_url)
|
||||
async with connection:
|
||||
channel = await connection.channel()
|
||||
await channel.set_qos(prefetch_count=20)
|
||||
exchange, queue, dlx = await declare_sms_topology(channel)
|
||||
client = KavenegarSmsClient(settings.kavenegar_api_key)
|
||||
await queue.consume(lambda message: handle_message(message, client, exchange, dlx))
|
||||
logger.info("SMS worker started")
|
||||
await asyncio.Future()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
Reference in New Issue
Block a user