From 690a1a4ad86db97a01ec5bd0c72f156414b3b60e Mon Sep 17 00:00:00 2001 From: vrtornisiello Date: Fri, 13 Feb 2026 14:04:40 -0300 Subject: [PATCH 1/6] fix: rename logging.py to log_config.py to avoid shadowing stdlib logging module --- app/{logging.py => log_config.py} | 0 app/main.py | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) rename app/{logging.py => log_config.py} (100%) diff --git a/app/logging.py b/app/log_config.py similarity index 100% rename from app/logging.py rename to app/log_config.py diff --git a/app/main.py b/app/main.py index 666efef..85bcf23 100644 --- a/app/main.py +++ b/app/main.py @@ -13,7 +13,7 @@ from app.agent.tools import BDToolkit from app.api.main import api_router from app.db.database import engine, init_database -from app.logging import setup_logger +from app.log_config import setup_logger from app.settings import settings setup_logger() From d7e2af0f2951c8eb3f0743cdeff9aa663c0ebb95 Mon Sep 17 00:00:00 2001 From: vrtornisiello Date: Fri, 13 Feb 2026 14:04:57 -0300 Subject: [PATCH 2/6] fix: remove checkpointer.setup() and set dict_row as row factory --- app/main.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/app/main.py b/app/main.py index 85bcf23..3f10c11 100644 --- a/app/main.py +++ b/app/main.py @@ -5,6 +5,7 @@ from langchain.chat_models import init_chat_model from langgraph.checkpoint.postgres.aio import AsyncPostgresSaver from loguru import logger +from psycopg.rows import dict_row from psycopg_pool import AsyncConnectionPool from app.agent import ReActAgent @@ -38,7 +39,11 @@ async def lifespan(app: FastAPI): # pragma: no cover # Connection kwargs defined according to: # https://github.com/langchain-ai/langgraph/issues/2887 # https://langchain-ai.github.io/langgraph/how-tos/persistence_postgres - conn_kwargs = {"autocommit": True, "prepare_threshold": 0} + conn_kwargs = { + "autocommit": True, + "prepare_threshold": 0, + "row_factory": dict_row, + } model = init_chat_model( model=settings.MODEL_URI, @@ -51,8 +56,6 @@ async def lifespan(app: FastAPI): # pragma: no cover ) as pool: checkpointer = AsyncPostgresSaver(pool) - await checkpointer.setup() - agent = ReActAgent( model=model, tools=BDToolkit.get_tools(), From 149e0ab93286db32e288b287ebad3a2b8c40e8c8 Mon Sep 17 00:00:00 2001 From: vrtornisiello Date: Fri, 13 Feb 2026 14:07:43 -0300 Subject: [PATCH 3/6] feat: log errors raised during lifespan events --- app/main.py | 86 ++++++++++++++++++++++++++++------------------------- 1 file changed, 45 insertions(+), 41 deletions(-) diff --git a/app/main.py b/app/main.py index 3f10c11..c01fb91 100644 --- a/app/main.py +++ b/app/main.py @@ -22,53 +22,57 @@ @asynccontextmanager async def lifespan(app: FastAPI): # pragma: no cover - if settings.AUTH_DEV_MODE and settings.ENVIRONMENT == "development": - logger.warning( - "AUTH DEV MODE ENABLED: JWT validation is bypassed, " - f"all requests will use user_id={settings.AUTH_DEV_USER_ID}" + try: + if settings.AUTH_DEV_MODE and settings.ENVIRONMENT == "development": + logger.warning( + "AUTH DEV MODE ENABLED: JWT validation is bypassed, " + f"all requests will use user_id={settings.AUTH_DEV_USER_ID}" + ) + + if settings.AUTH_DEV_MODE and settings.ENVIRONMENT != "development": + logger.warning( + f"AUTH_DEV_MODE is enabled but ENVIRONMENT is '{settings.ENVIRONMENT}'. " + "Auth dev mode will be ignored." + ) + + await init_database(engine) + + # Connection kwargs defined according to: + # https://github.com/langchain-ai/langgraph/issues/2887 + # https://langchain-ai.github.io/langgraph/how-tos/persistence_postgres + conn_kwargs = { + "autocommit": True, + "prepare_threshold": 0, + "row_factory": dict_row, + } + + model = init_chat_model( + model=settings.MODEL_URI, + temperature=settings.MODEL_TEMPERATURE, + credentials=settings.GOOGLE_CREDENTIALS, ) - if settings.AUTH_DEV_MODE and settings.ENVIRONMENT != "development": - logger.warning( - f"AUTH_DEV_MODE is enabled but ENVIRONMENT is '{settings.ENVIRONMENT}'. " - "Auth dev mode will be ignored." - ) + async with AsyncConnectionPool( + conninfo=settings.DB_URL, max_size=8, kwargs=conn_kwargs + ) as pool: + checkpointer = AsyncPostgresSaver(pool) - await init_database(engine) - - # Connection kwargs defined according to: - # https://github.com/langchain-ai/langgraph/issues/2887 - # https://langchain-ai.github.io/langgraph/how-tos/persistence_postgres - conn_kwargs = { - "autocommit": True, - "prepare_threshold": 0, - "row_factory": dict_row, - } - - model = init_chat_model( - model=settings.MODEL_URI, - temperature=settings.MODEL_TEMPERATURE, - credentials=settings.GOOGLE_CREDENTIALS, - ) - - async with AsyncConnectionPool( - conninfo=settings.DB_URL, max_size=8, kwargs=conn_kwargs - ) as pool: - checkpointer = AsyncPostgresSaver(pool) - - agent = ReActAgent( - model=model, - tools=BDToolkit.get_tools(), - start_hook=trim_messages_before_agent, - system_prompt=SYSTEM_PROMPT, - checkpointer=checkpointer, - ) + agent = ReActAgent( + model=model, + tools=BDToolkit.get_tools(), + start_hook=trim_messages_before_agent, + system_prompt=SYSTEM_PROMPT, + checkpointer=checkpointer, + ) - app.state.agent = agent + app.state.agent = agent - yield + yield - await engine.dispose() + await engine.dispose() + except Exception: + logger.exception("Lifespan failed:") + raise app = FastAPI(lifespan=lifespan) From bead27435587f787c9d7687b2ba798f5b5cb1108 Mon Sep 17 00:00:00 2001 From: vrtornisiello Date: Fri, 13 Feb 2026 14:28:43 -0300 Subject: [PATCH 4/6] build: add migration and checkpointer setup scripts --- scripts/__init__.py | 0 scripts/migrate.sh | 10 ++++++++++ scripts/setup_checkpointer.py | 17 +++++++++++++++++ 3 files changed, 27 insertions(+) create mode 100644 scripts/__init__.py create mode 100755 scripts/migrate.sh create mode 100644 scripts/setup_checkpointer.py diff --git a/scripts/__init__.py b/scripts/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/scripts/migrate.sh b/scripts/migrate.sh new file mode 100755 index 0000000..50a9e9d --- /dev/null +++ b/scripts/migrate.sh @@ -0,0 +1,10 @@ +#!/usr/bin/env bash +set -euo pipefail + +printf "Running Alembic migrations...\n" +alembic upgrade head + +printf "Setting up LangGraph checkpointer...\n" +python -m scripts.setup_checkpointer + +printf "Migration completed successfully.\n" diff --git a/scripts/setup_checkpointer.py b/scripts/setup_checkpointer.py new file mode 100644 index 0000000..d16bd28 --- /dev/null +++ b/scripts/setup_checkpointer.py @@ -0,0 +1,17 @@ +""" +Run LangGraph checkpointer setup. `checkpointer.setup()` should be called only once. +Ref: https://docs.langchain.com/oss/python/langgraph/add-memory#example-using-postgres-checkpointer +""" + +from langgraph.checkpoint.postgres import PostgresSaver + +from app.settings import settings + + +def main(): + with PostgresSaver.from_conn_string(settings.DB_URL) as checkpointer: + checkpointer.setup() + + +if __name__ == "__main__": + main() From 3bf782c87a6934db3980a36f039b382ae2a47d85 Mon Sep 17 00:00:00 2001 From: vrtornisiello Date: Fri, 13 Feb 2026 14:32:46 -0300 Subject: [PATCH 5/6] chore: update migration service to run migration script --- compose.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compose.yaml b/compose.yaml index 9b1b9cb..c8b21e3 100644 --- a/compose.yaml +++ b/compose.yaml @@ -24,7 +24,7 @@ services: migration: build: . - command: alembic upgrade head + command: ./scripts/migrate.sh env_file: .env depends_on: database: From d25b1562a8c39288a857d162e1a1697397977573 Mon Sep 17 00:00:00 2001 From: vrtornisiello Date: Fri, 13 Feb 2026 14:34:08 -0300 Subject: [PATCH 6/6] build: update migration job to run migration script --- charts/basedosdados-chatbot/templates/migration.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/charts/basedosdados-chatbot/templates/migration.yaml b/charts/basedosdados-chatbot/templates/migration.yaml index bc299aa..f0819bd 100644 --- a/charts/basedosdados-chatbot/templates/migration.yaml +++ b/charts/basedosdados-chatbot/templates/migration.yaml @@ -19,7 +19,7 @@ spec: - name: basedosdados-chatbot-migration image: "{{ .Values.chatbot.image.name }}:{{ .Values.chatbot.image.tag }}" imagePullPolicy: {{ .Values.chatbot.image.pullPolicy }} - command: ["alembic", "upgrade", "head"] + command: ["./scripts/migrate.sh"] env: - name: JWT_ALGORITHM valueFrom: