Skip to content
This repository was archived by the owner on Feb 18, 2026. It is now read-only.

Commit 482fcc8

Browse files
committed
Close redis after tests
1 parent c0d663a commit 482fcc8

2 files changed

Lines changed: 42 additions & 4 deletions

File tree

.gitignore

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,3 @@ local
9696
tests/test_loki_generated.py
9797
tests/loki_generated_calls.json
9898
tests/migration_timing_report.json
99-
clients/python/MIGRATION_ISSUES.md
100-
CRITICAL_ISSUES_SUMMARY.md
101-
COMPATIBILITY_ANALYSIS.md
102-
clients/python/COMPATIBILITY_QUICK_REFERENCE.md

gsrest/app.py

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import logging.handlers
55
import os
66
import re
7+
import traceback
78
from contextlib import asynccontextmanager
89
from typing import Any, Optional
910

@@ -363,6 +364,11 @@ async def teardown_database(app: FastAPI):
363364
logger.info(app.state.tagstore_engine.pool.status())
364365
logger.info("Closed Tagstore connection.")
365366

367+
# Close Redis client if it exists
368+
if getattr(app.state, "redis_client", None):
369+
await app.state.redis_client.aclose()
370+
logger.info("Closed Redis connection.")
371+
366372

367373
class ConceptsCacheServiceFastAPI(ConceptProtocol):
368374
"""FastAPI-compatible concepts cache service"""
@@ -407,6 +413,9 @@ async def setup_services(app: FastAPI):
407413
redis_client = None
408414
log_tag_access_prefix = None
409415

416+
# Store redis_client on app.state for cleanup during shutdown
417+
app.state.redis_client = redis_client
418+
410419
app.state.services = ServiceContainer(
411420
config=config,
412421
db=app.state.db,
@@ -465,6 +474,7 @@ async def setup_plugins(app: FastAPI):
465474
setup_gen = subcl.setup(setup_args)
466475
if hasattr(setup_gen, "__anext__"):
467476
await setup_gen.__anext__()
477+
app.state.plugin_cleanup_generators.append(setup_gen)
468478

469479

470480
@asynccontextmanager
@@ -478,21 +488,40 @@ async def lifespan(app: FastAPI):
478488
yield
479489

480490
# Shutdown
491+
# Close plugin cleanup generators
492+
for gen in getattr(app.state, "plugin_cleanup_generators", []):
493+
try:
494+
await gen.aclose()
495+
except Exception as e:
496+
logger.warning(f"Error closing plugin generator: {e}")
497+
481498
await teardown_database(app)
482499

483500

501+
def _get_request_context(request: Request) -> str:
502+
"""Get user and URL context for error logging."""
503+
username = request.headers.get("X-Consumer-Username", "unknown")
504+
return f"URL: {request.url} | User: {username}"
505+
506+
484507
def _register_exception_handlers(app: FastAPI):
485508
"""Register common exception handlers on the app"""
486509

487510
@app.exception_handler(NotFoundException)
488511
async def not_found_handler(request: Request, exc: NotFoundException):
512+
logger.warning(
513+
f"NotFoundException: {exc.get_user_msg()} | {_get_request_context(request)}"
514+
)
489515
return JSONResponse(
490516
status_code=404,
491517
content={"detail": exc.get_user_msg()},
492518
)
493519

494520
@app.exception_handler(BadUserInputException)
495521
async def bad_input_handler(request: Request, exc: BadUserInputException):
522+
logger.warning(
523+
f"BadUserInputException: {exc.get_user_msg()} | {_get_request_context(request)}"
524+
)
496525
return JSONResponse(
497526
status_code=400,
498527
content={"detail": exc.get_user_msg()},
@@ -502,18 +531,31 @@ async def bad_input_handler(request: Request, exc: BadUserInputException):
502531
async def feature_not_available_handler(
503532
request: Request, exc: FeatureNotAvailableException
504533
):
534+
logger.warning(
535+
f"FeatureNotAvailableException: {exc.get_user_msg()} | {_get_request_context(request)}"
536+
)
505537
return JSONResponse(
506538
status_code=400,
507539
content={"detail": exc.get_user_msg()},
508540
)
509541

510542
@app.exception_handler(GsTimeoutException)
511543
async def timeout_handler(request: Request, exc: GsTimeoutException):
544+
logger.warning(f"GsTimeoutException | {_get_request_context(request)}")
512545
return JSONResponse(
513546
status_code=408,
514547
content={"detail": "Request timeout"},
515548
)
516549

550+
@app.exception_handler(Exception)
551+
async def unhandled_exception_handler(request: Request, exc: Exception):
552+
tb = "".join(traceback.format_exception(type(exc), exc, exc.__traceback__))
553+
logger.error(f"Unhandled exception | {_get_request_context(request)}\n{tb}")
554+
return JSONResponse(
555+
status_code=500,
556+
content={"detail": "Internal server error"},
557+
)
558+
517559

518560
def _register_routers(app: FastAPI):
519561
"""Register all API routers on the app.

0 commit comments

Comments
 (0)