import fastapi import sentry_sdk from chat_daemon_tools.gunicorn_runner import GenericGunicornRunner from chat_log_tools import middleware as log_middleware from chat_log_tools import setup_json_logger from fastapi import status from fastapi_rest_versioning import VersionedFastAPI, set_accept_header from health_checks.api.fastapi import get_health_check_router from kerberos_tools import client as kerberos_client from opentelemetry import trace from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import OTLPSpanExporter from opentelemetry.instrumentation.aiohttp_client import AioHttpClientInstrumentor from opentelemetry.instrumentation.asyncpg import AsyncPGInstrumentor from opentelemetry.instrumentation.fastapi import FastAPIInstrumentor from opentelemetry.instrumentation.psycopg2 import Psycopg2Instrumentor from opentelemetry.sdk.resources import SERVICE_NAME, Resource from opentelemetry.sdk.trace import TracerProvider from opentelemetry.sdk.trace.export import BatchSpanProcessor from platform_jwt_tools import security from sentry_sdk.integrations.asgi import SentryAsgiMiddleware from starlette.middleware.cors import CORSMiddleware from dialogs import ioc, settings from dialogs.api import bot, dialogs, error_handlers, internal, messages, mobile from dialogs.services import messages as messages_service # pylint: disable=no-member _KERBEROS_RENEWAL_TASK: asyncio.Task | None = None CONTAINER: ioc.IOCContainer = ioc.IOCContainer() async def startup(): """Global initialization.""" if settings.KAFKA_USE_KERBEROS: global _KERBEROS_RENEWAL_TASK # pylint: disable=global-statement _KERBEROS_RENEWAL_TASK = await kerberos_client.issue_ticket_and_run_renewal_task( settings.KAFKA_KERBEROS_PRINCIPAL, pathlib.Path(settings.KAFKA_KERBEROS_KEYTAB_PATH), settings.KAFKA_KERBEROS_RENEWAL_INTERVAL_SECONDS, ) await CONTAINER.init_resources() CONTAINER.wire(modules=[dialogs, messages, internal, mobile, messages_service, bot]) async def shutdown(): """Global shutdown.""" if _KERBEROS_RENEWAL_TASK: _KERBEROS_RENEWAL_TASK.cancel() await CONTAINER.shutdown_resources() if settings.SENTRY_DSN: sentry_sdk.init(dsn=settings.SENTRY_DSN, default_integrations=False) # pylint: disable=E0110 set_accept_header(settings.PLATFORM_ACCEPT_HEADER) APP_OBJ: fastapi.FastAPI = VersionedFastAPI( docs_url=settings.DOC_PREFIX, on_startup=[startup], on_shutdown=[shutdown], openapi_url=f"{settings.API_PREFIX}/openapi.json", openapi_tags=settings.TAGS_METADATA, exception_handlers={status.HTTP_500_INTERNAL_SERVER_ERROR: error_handlers.handle_500_exception}, ) APP_OBJ.include_router(dialogs.ROUTER_OBJ, prefix=settings.API_PREFIX, tags=["dialogs"]) APP_OBJ.include_router(messages.ROUTER_OBJ, prefix=settings.API_PREFIX, tags=["messages"]) APP_OBJ.include_router(get_health_check_router(), prefix=settings.API_PREFIX, tags=["health"]) APP_OBJ.include_router(internal.ROUTER_OBJ, prefix=settings.INTERNAL_API_PREFIX, tags=["internal"]) APP_OBJ.include_router(mobile.ROUTER_OBJ, prefix=settings.MOBILE_API_PREFIX, tags=["mobile"]) APP_OBJ.include_router(bot.ROUTER_OBJ, prefix=settings.BOT_API_PREFIX, tags=["bot"]) APP_OBJ.add_middleware(log_middleware.RequestIDASGIMiddleware) APP_OBJ.add_middleware(SentryAsgiMiddleware) if settings.OPENTELEMETRY_ENDPOINT: EXPORTER: OTLPSpanExporter = OTLPSpanExporter(endpoint=settings.OPENTELEMETRY_ENDPOINT, insecure=True) TRACE_PROVIDER: TracerProvider = TracerProvider( resource=Resource.create( { SERVICE_NAME: settings.OPENTELEMETRY_SERVICE_NAME, } ) ) TRACE_PROVIDER.add_span_processor(BatchSpanProcessor(EXPORTER)) trace.set_tracer_provider(TRACE_PROVIDER) FastAPIInstrumentor.instrument_app(APP_OBJ) AioHttpClientInstrumentor().instrument() AsyncPGInstrumentor().instrument() Psycopg2Instrumentor().instrument() if settings.DEBUG: APP_OBJ.add_middleware( CORSMiddleware, allow_origins=["*"], allow_credentials=True, allow_methods=["*"], allow_headers=["*"], ) if __name__ == "__main__": server: GenericGunicornRunner = GenericGunicornRunner( APP_OBJ, f"0.0.0.0:{settings.APP_PORT}", workers=settings.APP_WORKERS, loglevel=settings.APP_LOG_LEVEL ) setup_json_logger(need_sentry=bool(settings.SENTRY_DSN)) security.set_jwt_public_key(settings.JWT_PUBLIC_KEY) server.run()