Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

DM-47716: Move auth metrics reporting to a background task #1163

Merged
merged 1 commit into from
Nov 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions changelog.d/20241122_105538_rra_DM_47716.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
### Bug fixes

- Move metrics reporting for hot-path authentication events to a background task so that it happens in parallel with the HTTP response.
53 changes: 38 additions & 15 deletions src/gafaelfawr/handlers/ingress.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,15 @@
from datetime import timedelta
from typing import Annotated

import sentry_sdk
from fastapi import APIRouter, Depends, Header, HTTPException, Query, Response
from fastapi import (
APIRouter,
BackgroundTasks,
Depends,
Header,
HTTPException,
Query,
Response,
)
from safir.datetime import current_datetime
from safir.models import ErrorModel
from safir.slack.webhook import SlackRouteErrorHandler
Expand All @@ -27,7 +34,7 @@
from ..constants import MINIMUM_LIFETIME
from ..dependencies.auth import AuthenticateRead
from ..dependencies.context import RequestContext, context_dependency
from ..events import AuthBotEvent, AuthUserEvent
from ..events import AuthBotEvent, AuthUserEvent, FrontendEvents
from ..exceptions import (
ExternalUserInfoError,
InsufficientScopeError,
Expand Down Expand Up @@ -305,6 +312,30 @@ async def authenticate_with_type(
return await authenticate(context=context)


async def publish_auth_event(
events: FrontendEvents, auth_config: AuthConfig, token_data: TokenData
) -> None:
"""Publish metrics events for a successful authentication.

Parameters
----------
events
Event manager.
auth_config
Requested authentication parameters.
token_data
Successful authentication data.
"""
username = token_data.username
service = auth_config.service
if is_bot_user(token_data.username):
bot_event = AuthBotEvent(username=username, service=service)
await events.auth_bot.publish(bot_event)
else:
user_event = AuthUserEvent(username=username, service=service)
await events.auth_user.publish(user_event)


@router.get(
"/ingress/auth",
description="Meant to be used as an NGINX auth_request handler",
Expand All @@ -322,6 +353,7 @@ async def get_auth(
token_data: Annotated[TokenData, Depends(authenticate_with_type)],
context: Annotated[RequestContext, Depends(context_dependency)],
response: Response,
background_tasks: BackgroundTasks,
) -> dict[str, str]:
check_lifetime(context, auth_config, token_data)

Expand Down Expand Up @@ -360,18 +392,9 @@ async def get_auth(
headers = await build_success_headers(context, auth_config, token_data)
for key, value in headers:
response.headers.append(key, value)

with sentry_sdk.start_span(name="events.publish"):
if is_bot_user(token_data.username):
bot_event = AuthBotEvent(
username=token_data.username, service=auth_config.service
)
await context.events.auth_bot.publish(bot_event)
else:
user_event = AuthUserEvent(
username=token_data.username, service=auth_config.service
)
await context.events.auth_user.publish(user_event)
background_tasks.add_task(
publish_auth_event, context.events, auth_config, token_data
)
return {"status": "ok"}


Expand Down