Реализация на отдельных двух машинах с протестированным взаимодействием по проверке сообщений
This commit is contained in:
@@ -1,5 +1,7 @@
|
||||
import asyncio
|
||||
import uuid
|
||||
from collections.abc import AsyncIterator
|
||||
from contextlib import asynccontextmanager
|
||||
from datetime import UTC, datetime, timedelta
|
||||
|
||||
import httpx
|
||||
@@ -26,12 +28,28 @@ from app.integrations import (
|
||||
from app.notification_models import ClientUploadDraft
|
||||
from app.notification_service import expire_notifications
|
||||
from app.realtime import RealtimeFanout
|
||||
from app.services import load_settings, publish_dialog_status, publish_message_status
|
||||
from app.services import (
|
||||
ensure_delivery_outbox,
|
||||
load_settings,
|
||||
publish_dialog_status,
|
||||
publish_message_status,
|
||||
)
|
||||
from app.settings import Settings, get_settings
|
||||
|
||||
log = structlog.get_logger()
|
||||
|
||||
|
||||
@asynccontextmanager
|
||||
async def worker_http_clients(
|
||||
settings: Settings,
|
||||
) -> AsyncIterator[tuple[httpx.AsyncClient, httpx.AsyncClient]]:
|
||||
async with (
|
||||
httpx.AsyncClient() as openlines_http,
|
||||
httpx.AsyncClient(verify=settings.message_safety_ca_file) as safety_http,
|
||||
):
|
||||
yield openlines_http, safety_http
|
||||
|
||||
|
||||
async def delivery_once(
|
||||
db: Database,
|
||||
client: OpenLinesClient,
|
||||
@@ -171,37 +189,38 @@ async def safety_once(
|
||||
else None
|
||||
)
|
||||
if dialog and user:
|
||||
session.add(
|
||||
DeliveryOutbox(
|
||||
message_id=message.id,
|
||||
external_chat_id=dialog.id,
|
||||
payload_json={
|
||||
"message_id": str(message.id),
|
||||
"external_chat_id": str(dialog.id),
|
||||
"occurred_at": message.occurred_at.isoformat(),
|
||||
"user": {
|
||||
"id": str(user.id),
|
||||
"display_name": user.phone_number,
|
||||
},
|
||||
"message": {
|
||||
"content_kind": message.content_kind,
|
||||
"text": message.text,
|
||||
"files": (
|
||||
[{
|
||||
await ensure_delivery_outbox(
|
||||
session,
|
||||
message_id=message.id,
|
||||
external_chat_id=dialog.id,
|
||||
payload_json={
|
||||
"message_id": str(message.id),
|
||||
"external_chat_id": str(dialog.id),
|
||||
"occurred_at": message.occurred_at.isoformat(),
|
||||
"user": {
|
||||
"id": str(user.id),
|
||||
"display_name": user.phone_number,
|
||||
},
|
||||
"message": {
|
||||
"content_kind": message.content_kind,
|
||||
"text": message.text,
|
||||
"files": (
|
||||
[
|
||||
{
|
||||
"attachment_id": str(attachment.id),
|
||||
"name": attachment.safe_file_name,
|
||||
"mime_type": attachment.mime_type,
|
||||
"size_bytes": attachment.size_bytes,
|
||||
"_storage_bucket": attachment.storage_bucket,
|
||||
"_object_key": attachment.object_key,
|
||||
}]
|
||||
if attachment
|
||||
else []
|
||||
),
|
||||
},
|
||||
}
|
||||
]
|
||||
if attachment
|
||||
else []
|
||||
),
|
||||
},
|
||||
next_attempt_at=datetime.now(UTC),
|
||||
)
|
||||
},
|
||||
next_attempt_at=datetime.now(UTC),
|
||||
)
|
||||
elif verdict["_status"] == 403 and message:
|
||||
message.safety_processing_mode = verdict["processing_mode"]
|
||||
@@ -270,26 +289,25 @@ async def cleanup_once(db: Database, s3: S3Client, batch_size: int = 100) -> int
|
||||
async def loop(kind: str) -> None:
|
||||
settings = get_settings()
|
||||
db = Database(settings.database_url)
|
||||
http = httpx.AsyncClient()
|
||||
safety = SafetyClient(settings, http)
|
||||
openlines = OpenLinesClient(settings, http)
|
||||
s3 = S3Client(settings)
|
||||
redis_rt = redis.from_url(settings.redis_realtime_url, decode_responses=True)
|
||||
fanout = RealtimeFanout(redis_rt)
|
||||
worker_id = f"{kind}-{uuid.uuid4()}"
|
||||
try:
|
||||
while True:
|
||||
count = 0
|
||||
if kind == "delivery":
|
||||
count = await delivery_once(db, openlines, s3, fanout, settings, worker_id)
|
||||
elif kind == "safety":
|
||||
count = await safety_once(db, safety, s3, fanout, settings, worker_id)
|
||||
else:
|
||||
count = await cleanup_once(db, s3)
|
||||
if not count:
|
||||
await asyncio.sleep(settings.worker_poll_interval_sec)
|
||||
async with worker_http_clients(settings) as (openlines_http, safety_http):
|
||||
safety = SafetyClient(settings, safety_http)
|
||||
openlines = OpenLinesClient(settings, openlines_http)
|
||||
while True:
|
||||
count = 0
|
||||
if kind == "delivery":
|
||||
count = await delivery_once(db, openlines, s3, fanout, settings, worker_id)
|
||||
elif kind == "safety":
|
||||
count = await safety_once(db, safety, s3, fanout, settings, worker_id)
|
||||
else:
|
||||
count = await cleanup_once(db, s3)
|
||||
if not count:
|
||||
await asyncio.sleep(settings.worker_poll_interval_sec)
|
||||
finally:
|
||||
await http.aclose()
|
||||
await redis_rt.aclose()
|
||||
await db.close()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user