Added pulling notifications from new backend-pull-notifications service

This commit is contained in:
florian committed 2026-10-12 09:52:08 +02:00
1 parent 71ec05978b
commit 8aec7bafce
2 files changed
+60 -3

No files matched your search

+3
View File
@@ -5,10 +5,13 @@ annotated-types==0.7.0
anyio==4.11.0 anyio==4.11.0
argon2-cffi==25.1.0 argon2-cffi==25.1.0
argon2-cffi-bindings==25.1.0 argon2-cffi-bindings==25.1.0
certifi==2026.7.22
cffi==2.0.0 cffi==2.0.0
click==8.3.0 click==8.3.0
fastapi==0.119.0 fastapi==0.119.0
h11==0.16.0 h11==0.16.0
httpcore==1.0.9
httpx==0.28.1
idna==3.11 idna==3.11
lib-db-module==0.2.0 lib-db-module==0.2.0
lib-secret-manager==0.2.0 lib-secret-manager==0.2.0
+57 -3
View File
@@ -3,7 +3,7 @@ from fastapi.responses import JSONResponse
from fastapi.security.api_key import APIKeyHeader from fastapi.security.api_key import APIKeyHeader
from starlette.exceptions import HTTPException as StarletteHTTPException from starlette.exceptions import HTTPException as StarletteHTTPException
from typing import Dict from typing import Dict
from pydantic import BaseModel from pydantic import BaseModel, Field
from validator import verify_api_key from validator import verify_api_key
from db_module import get_db, create_connection_pool, close_connection_pool, start_healthcheck_thread from db_module import get_db, create_connection_pool, close_connection_pool, start_healthcheck_thread
from simple_logger_handler import setup_logger, LOG_LEVEL from simple_logger_handler import setup_logger, LOG_LEVEL
@@ -14,15 +14,29 @@ from metrics_server import REQUEST_COUNTER
import asyncio import asyncio
from uvicorn_logger_config import LOGGING_CONFIG from uvicorn_logger_config import LOGGING_CONFIG
from secret_manager import cleanup_secret_files from secret_manager import cleanup_secret_files
import httpx
import os
logger = setup_logger(__name__) logger = setup_logger(__name__)
api_key_header_internal = APIKeyHeader(name="X-API-Key-Internal") api_key_header_internal = APIKeyHeader(name="X-API-Key-Internal")
PULL_SERVICE_URL = os.getenv(
"BACKEND_PULL_NOTIFICATIONS_URL",
"http://backend-pull-notifications.app-notifications.svc.cluster.local:8101",
)
MAX_PAGES = 5
class Notification(BaseModel): class Notification(BaseModel):
receipent_user_id : int receipent_user_id : int = Field(gt=0) #ToDo fix among all services
message : Dict message : Dict
class PullResponse(BaseModel):
messages: list[dict]
count: int
has_more: bool
class PullRequest(BaseModel):
user_id: int = Field(gt=0)
@asynccontextmanager @asynccontextmanager
async def lifespan(app: FastAPI): async def lifespan(app: FastAPI):
@@ -41,6 +55,12 @@ async def lifespan(app: FastAPI):
app.state.rmq_producer = producer app.state.rmq_producer = producer
logger.info("[FastAPI] RabbitMQ producer initialized.") logger.info("[FastAPI] RabbitMQ producer initialized.")
app.state.http_client = httpx.AsyncClient (
base_url=PULL_SERVICE_URL,
timeout=httpx.Timeout(10.0,connect=3.0)
)
logger.info("[FastAPI] HTTP client initialized.")
SECRET_PATHS = frozenset({ SECRET_PATHS = frozenset({
"/etc/secrets/db_username", "/etc/secrets/db_username",
"/etc/secrets/db_password", "/etc/secrets/db_password",
@@ -57,6 +77,9 @@ async def lifespan(app: FastAPI):
logger.info("Closing MySQL connection pool...") logger.info("Closing MySQL connection pool...")
close_connection_pool() close_connection_pool()
await app.state.http_client.aclose()
logger.info("[FastAPI] Closing Http client")
api = FastAPI( api = FastAPI(
title="Internal Notifier API", title="Internal Notifier API",
description="API to forward messages to RabbitMQ", description="API to forward messages to RabbitMQ",
@@ -104,7 +127,7 @@ async def custom_http_exception_handler(request,exc):
content={"detail": exc.detail} content={"detail": exc.detail}
) )
@api.post("/internal/receive-notifications") @api.post("/internal/receive-notifications") #ToDo fix among all services
async def receive_notifications( async def receive_notifications(
notification_data: Notification, notification_data: Notification,
request: Request, request: Request,
@@ -121,6 +144,37 @@ async def receive_notifications(
logger.info("Successfully queued for delivery to RMQ") logger.info("Successfully queued for delivery to RMQ")
return {"status": "queued"} return {"status": "queued"}
@api.post("/internal/pull-notifications", response_model=PullResponse)
async def pull_notifications(
pull_request: PullRequest,
request: Request,
program_name: str = Depends(verify_api_key_dependency_internal),
):
user_id = pull_request.user_id
logger.debug(f"[FastAPI] User id {user_id} is requesting messages")
client: httpx.AsyncClient = request.app.state.http_client
messages: list[dict] = []
has_more = False
try:
for _ in range(MAX_PAGES):
resp = await client.post("/internal/pull-notifications", json={"user_id": user_id})
resp.raise_for_status()
data = PullResponse.model_validate(resp.json())
messages.extend(data.messages)
has_more = data.has_more
if not has_more:
break
except (httpx.HTTPError, ValueError) as e:
logger.error(f"[FastAPI] Pull service failed for user_id={user_id}: {e!r}")
status = 504 if isinstance(e, httpx.TimeoutException) else 502
raise HTTPException(status_code=status, detail="Notification service unavailable")
logger.info(f"[FastAPI] Returning {len(messages)} message(s) for user_id={user_id}, has_more={has_more}")
return PullResponse(messages=messages, count=len(messages), has_more=has_more)
async def start_servers(): async def start_servers():
logger.debug("Starting FastAPI and metrics servers") logger.debug("Starting FastAPI and metrics servers")
config_main = uvicorn.Config("main:api", host="0.0.0.0", port=8101, log_level=LOG_LEVEL.lower(), log_config=LOGGING_CONFIG) config_main = uvicorn.Config("main:api", host="0.0.0.0", port=8101, log_level=LOG_LEVEL.lower(), log_config=LOGGING_CONFIG)