Skip to content

fix(database): fixes pool related checks, duplicated function calls and session management#9983

Closed
ogabrielluiz wants to merge 15 commits into
mainfrom
improve-db-pool
Closed

fix(database): fixes pool related checks, duplicated function calls and session management#9983
ogabrielluiz wants to merge 15 commits into
mainfrom
improve-db-pool

Conversation

@ogabrielluiz
Copy link
Copy Markdown
Contributor

@ogabrielluiz ogabrielluiz commented Sep 25, 2025

This pull request focuses on improving database session management and usage patterns across the codebase. The main changes involve removing the legacy session_getter context manager and standardizing on the new session_scope context manager, which delegates session lifecycle management to DatabaseService.with_session(). Additionally, there are improvements to connection pooling logic and transaction handling.

Database session management and context usage:

  • Removed the obsolete session_getter context manager from src/backend/base/langflow/services/database/utils.py and updated all references to use session_scope instead, ensuring consistent session handling throughout the backend and tests. [1] [2] [3] [4] [5] [6] [7] [8] [9] [10] [11] [12] [13]

  • Updated the implementation and documentation of session_scope in src/backend/base/langflow/services/deps.py to clarify its delegation to DatabaseService.with_session(), which now centrally manages commits and rollbacks. [1] [2]

Transaction and error handling improvements:

  • Modified transaction logging and cleanup functions to let the caller manage commits and rollbacks, improving error logging and propagation. This affects transaction CRUD and utility functions. [1] [2]

Connection pooling logic:

  • Improved pool class selection in DatabaseService._create_engine to use issubclass instead of instantiating pool classes, and to remove invalid pool class specifications, ensuring robust engine creation.
  • Enhanced SQLAlchemy engine creation in src/lfx/src/lfx/components/langchain_utilities/sql_database.py to use NullPool for PostgreSQL connections and StaticPool for others, preventing unnecessary persistent connections. [1] [2]

Websocket authentication session management:

  • Updated websocket endpoints in src/backend/base/langflow/api/v1/voice_mode.py to use a short-lived session for authentication, removing the need to pass a session object through the call stack. [1] [2] [3] [4] [5] [6]

These changes collectively modernize and standardize database session handling, reduce boilerplate, and improve reliability and maintainability of database interactions.

Summary by CodeRabbit

  • New Features
    • Adaptive database connection pooling based on database type for smoother performance.
  • Bug Fixes
    • Improved stability and concurrency in voice/websocket interactions and message logging.
    • Reduced risk of connection leaks and pool misconfiguration.
  • Refactor
    • Standardized short‑lived, scoped database sessions across services and websockets.
    • Simplified transaction handling and clarified session lifecycle behavior.
  • Tests
    • Updated tests to use the new session scope for consistency and reliability.
  • Chores
    • Removed deprecated session helpers and unnecessary logging dependencies.

Updated the poolclass validation in DatabaseService to check for subclasses of sa.pool.Pool instead of instances. Additionally, removed invalid poolclass from kwargs to ensure the default pool class is used when an invalid value is specified. This change enhances the robustness of the database connection handling.
…gine

Refactored the poolclass selection in the SQLDatabaseComponent to dynamically choose between NullPool for PostgreSQL and StaticPool for other databases. This change improves connection management by ensuring that connections are closed after use for PostgreSQL, enhancing resource efficiency and robustness in database interactions.
Removed the session parameter from `flow_as_tool_websocket_no_session` and `flow_tts_websocket_no_session` functions. Updated the WebSocket handling to utilize a short-lived session context for user authentication, enhancing code clarity and maintaining robust session management. This change improves the overall structure and readability of the WebSocket endpoints.
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Sep 25, 2025

Important

Review skipped

Auto incremental reviews are disabled on this repository.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Walkthrough

Refactors WebSocket voice endpoints to use ephemeral, context-managed DB sessions (removing DbSession params), updates engine poolclass handling to accept/import classes and validate with issubclass, conditionally selects SQLAlchemy pool class (NullPool for Postgres, StaticPool otherwise), and replaces several internal session utilities with session_scope. Other transactional commit/rollback calls were removed in a few DB utility functions and tests updated accordingly.

Changes

Cohort / File(s) Summary
WebSocket handlers (voice_mode)
src/backend/base/langflow/api/v1/voice_mode.py
Removed persistent session: DbSession parameters from four WS handlers and updated them to create and use async with session_scope() for authentication, key lookup, message saves, and cleanup; per-message DB writes also use ephemeral scoped sessions.
DB engine creation & poolclass validation
src/backend/base/.../services/database/service.py
_create_engine now accepts string or class poolclass, dynamically imports dotted paths, validates via issubclass(sa.pool.Pool), and sets poolclass only if valid; minor comment removal in with_session.
Dynamic SQLAlchemy pool selection
src/lfx/src/lfx/components/langchain_utilities/sql_database.py
build_sqldatabase parses URI with make_url and selects NullPool for Postgres URIs, StaticPool otherwise; passes chosen poolclass to create_engine.
Transaction logging behavior
src/backend/base/.../transactions/crud.py
log_transaction removed explicit await db.commit() after delete and replaced simple rollback with logger.exception logging in exception path.
Database init/session utilities
src/backend/base/.../services/database/utils.py, src/backend/base/.../services/deps.py
Removed local session_getter and switched callers to session_scope import; session_scope docstring clarified and logger exception call removed; callers updated to async with session_scope().
Service utils transaction handling
src/backend/base/.../services/utils.py
clean_transactions no longer calls session.commit() on success and now re-raises exceptions after logging; previous rollback/commit steps removed.
Tests updated to use session_scope
src/backend/tests/conftest.py, src/backend/tests/unit/test_database.py, src/backend/tests/unit/test_user.py
Replaced session_getter(get_db_service()) usages with session_scope() in fixtures and tests; imports adjusted accordingly.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  participant C as Client
  participant E as WS Endpoint
  participant SS as session_scope()
  participant A as Auth / Key lookup
  participant F as Flow/TTS Handler
  participant DB as Database

  C->>E: Open WebSocket (flow_id)
  activate E
  E->>SS: async with session_scope()  (open ephemeral session)
  activate SS
  SS->>A: get_current_user_for_websocket(session)
  A-->>SS: user / error
  alt auth ok
    SS-->>E: proceed
    E->>F: handle messages/events
    loop per message
      F->>SS: save message (uses new ephemeral session via session_scope for each save)
      SS->>DB: INSERT/UPDATE
      DB-->>SS: ack
      SS-->>F: saved
    end
    F-->>C: stream audio/text
  else auth fail
    SS-->>E: send error & close
  end
  note over E,SS: On close/cleanup: reopen session_scope() to fetch auth/info for cleanup
  deactivate SS
  deactivate E
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested labels

refactor, lgtm, size:XXL

Suggested reviewers

  • jordanrfrazier
  • rjordanfrazier
  • erichare

Pre-merge checks and finishing touches

❌ Failed checks (2 warnings)
Check name Status Explanation Resolution
Title Check ⚠️ Warning The title references pool related checks, duplicated function calls, and session management but the PR primarily modernizes database connection pooling and session handling while refactoring WebSocket session usage. Including “duplicated function calls” introduces noise as it is not a central change in the provided objectives. The phrasing is overly broad and lists multiple unrelated items, making the main update unclear for someone scanning the history. Please update the PR title to clearly highlight the primary improvements, such as standardizing session management and dynamic pool class selection. Removing references to “duplicated function calls” will help teammates quickly grasp the core changes. Consider using a concise Conventional Commit style title that reflects the central focus of the update.
Docstring Coverage ⚠️ Warning Docstring coverage is 30.43% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot changed the title @coderabbitai refactor(voice,db): Scoped session per WS; update pool config Sep 25, 2025
@codecov
Copy link
Copy Markdown

codecov Bot commented Sep 25, 2025

Codecov Report

❌ Patch coverage is 45.45455% with 30 lines in your changes missing coverage. Please review.
✅ Project coverage is 23.54%. Comparing base (75e2650) to head (7edd4c5).
⚠️ Report is 404 commits behind head on main.

Files with missing lines Patch % Lines
src/backend/base/langflow/api/v1/voice_mode.py 7.14% 26 Missing ⚠️
...c/backend/base/langflow/services/database/utils.py 0.00% 2 Missing ⚠️
...flow/services/database/models/transactions/crud.py 0.00% 1 Missing ⚠️
src/backend/base/langflow/services/utils.py 0.00% 1 Missing ⚠️

❌ Your project status has failed because the head coverage (45.78%) is below the target coverage (55.00%). You can increase the head coverage or adjust the target coverage.

Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##             main    #9983      +/-   ##
==========================================
- Coverage   23.68%   23.54%   -0.15%     
==========================================
  Files        1090     1090              
  Lines       39768    39784      +16     
  Branches     5542     5542              
==========================================
- Hits         9419     9366      -53     
- Misses      30178    30247      +69     
  Partials      171      171              
Flag Coverage Δ
backend 45.78% <45.45%> (-0.41%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ
...backend/base/langflow/services/database/service.py 66.07% <100.00%> (+3.49%) ⬆️
src/backend/base/langflow/services/deps.py 86.56% <100.00%> (+0.20%) ⬆️
...flow/services/database/models/transactions/crud.py 39.28% <0.00%> (+1.35%) ⬆️
src/backend/base/langflow/services/utils.py 77.10% <0.00%> (-0.14%) ⬇️
...c/backend/base/langflow/services/database/utils.py 55.10% <0.00%> (-3.24%) ⬇️
src/backend/base/langflow/api/v1/voice_mode.py 12.82% <7.14%> (-0.16%) ⬇️

... and 6 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 386d24d and c267d0f.

📒 Files selected for processing (3)
  • src/backend/base/langflow/api/v1/voice_mode.py (2 hunks)
  • src/backend/base/langflow/services/database/service.py (1 hunks)
  • src/lfx/src/lfx/components/langchain_utilities/sql_database.py (2 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
{src/backend/**/*.py,tests/**/*.py,Makefile}

📄 CodeRabbit inference engine (.cursor/rules/backend_development.mdc)

{src/backend/**/*.py,tests/**/*.py,Makefile}: Run make format_backend to format Python code before linting or committing changes
Run make lint to perform linting checks on backend Python code

Files:

  • src/backend/base/langflow/services/database/service.py
  • src/backend/base/langflow/api/v1/voice_mode.py
🧬 Code graph analysis (1)
src/backend/base/langflow/api/v1/voice_mode.py (2)
src/backend/base/langflow/services/deps.py (1)
  • session_scope (151-173)
src/backend/base/langflow/services/auth/utils.py (1)
  • get_current_user_for_websocket (222-245)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (12)
  • GitHub Check: Lint Backend / Run Mypy (3.11)
  • GitHub Check: Lint Backend / Run Mypy (3.12)
  • GitHub Check: Lint Backend / Run Mypy (3.13)
  • GitHub Check: Run Backend Tests / Unit Tests - Python 3.10 - Group 1
  • GitHub Check: Run Backend Tests / Unit Tests - Python 3.10 - Group 4
  • GitHub Check: Run Backend Tests / Unit Tests - Python 3.10 - Group 3
  • GitHub Check: Run Backend Tests / Unit Tests - Python 3.10 - Group 2
  • GitHub Check: Run Backend Tests / Unit Tests - Python 3.10 - Group 5
  • GitHub Check: Run Backend Tests / Integration Tests - Python 3.10
  • GitHub Check: Test Starter Templates
  • GitHub Check: Optimize new Python code in this PR
  • GitHub Check: Update Starter Projects
🔇 Additional comments (1)
src/lfx/src/lfx/components/langchain_utilities/sql_database.py (1)

3-3: LGTM: Import added

Importing NullPool alongside StaticPool is appropriate for dynamic pool selection.

Comment thread src/backend/base/langflow/api/v1/voice_mode.py
Comment thread src/backend/base/langflow/api/v1/voice_mode.py
Comment thread src/backend/base/langflow/services/database/service.py
Comment thread src/lfx/src/lfx/components/langchain_utilities/sql_database.py
…getter with session_scope

Updated the database utility functions to utilize session_scope for session management, enhancing code clarity and consistency across the codebase. This change improves the robustness of database interactions by standardizing session handling in both the database initialization and test files.
- Remove duplicate transaction management in session_scope()
  * Delegate to DatabaseService.with_session() which already handles commits/rollbacks
  * Prevents double commit/rollback that could cause connection issues

- Fix transaction CRUD to not manage its own transactions
  * Remove manual commit/rollback in log_transaction()
  * Let caller handle transaction lifecycle for better control

- Clean up transaction cleanup utility
  * Remove manual commit in clean_transactions()
  * Improve error handling and let caller manage transaction

These changes improve database connection pool efficiency by ensuring
consistent session lifecycle management and preventing connection leaks
from improper transaction handling.

Addresses connection pool exhaustion issues in high-scale deployments.
@ogabrielluiz ogabrielluiz changed the title refactor(voice,db): Scoped session per WS; update pool config fix(database): fixes pool related checks, duplicated function calls and session management Sep 25, 2025
@github-actions github-actions Bot added bug Something isn't working and removed bug Something isn't working labels Sep 25, 2025
Comment thread src/backend/base/langflow/api/v1/voice_mode.py
- Improved the session_scope context manager to include automatic commit on successful completion and rollback on exceptions, ensuring robust transaction management.
- Updated documentation to reflect the new transaction handling behavior, enhancing clarity for future developers.
- Removed redundant comments in the log_transaction function to streamline the code.

These changes contribute to better error handling and resource management in database interactions.
@github-actions github-actions Bot added bug Something isn't working and removed bug Something isn't working labels Sep 25, 2025
…tions

- Updated `flow_as_tool_websocket` and `flow_tts_websocket` to utilize a consistent short-lived session context for user authentication and database interactions.
- Replaced direct session parameter usage with `session_scope` in multiple database calls, enhancing code clarity and maintaining robust session management.
- Improved error handling by ensuring all database interactions are wrapped in session contexts, reducing the risk of connection leaks.

These changes contribute to better resource management and maintainability in the WebSocket handling logic.
…mponent

- Updated the poolclass selection logic to utilize `make_url` for better URI parsing, ensuring accurate identification of PostgreSQL databases.
- This change enhances connection management by correctly applying `NullPool` for PostgreSQL and `StaticPool` for other database types, improving resource efficiency and robustness in database interactions.
- Improved the poolclass selection logic to accept both class objects and string names/paths, allowing for more flexible configuration.
- Added error handling for dynamic imports of pool classes, ensuring robustness in cases where the specified class is not found.
- Updated logging to provide clearer feedback on the selected pool class, enhancing debugging capabilities.

These changes contribute to more versatile and reliable database connection management.
@github-actions github-actions Bot added bug Something isn't working and removed bug Something isn't working labels Sep 25, 2025
@ogabrielluiz
Copy link
Copy Markdown
Contributor Author

@coderabbitai could you review the new changes, please?

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Sep 25, 2025

🧩 Analysis chain

I'll review the new changes for you. Let me examine the modified files to provide comprehensive feedback.

@ogabrielluiz I'll review the changes in this PR. The improvements focus on database pool handling and WebSocket session management. Let me conduct a comprehensive review of all the changes.


🏁 Script executed:

#!/bin/bash
# First, let's look at the changes in the voice_mode.py file
echo "=== Changes in voice_mode.py ==="
cat src/backend/base/langflow/api/v1/voice_mode.py | head -50

echo -e "\n=== Looking for session_scope usage ==="
rg -n "session_scope" src/backend/base/langflow/api/v1/voice_mode.py -A 3 -B 1

echo -e "\n=== Looking for WebSocket endpoint signatures ==="
rg -n "def flow_.*websocket" src/backend/base/langflow/api/v1/voice_mode.py -A 2

Length of output: 5789


🏁 Script executed:

#!/bin/bash
# Examine the database service changes
echo "=== Changes in database service ==="
cat src/backend/base/langflow/services/database/service.py | grep -n -A 10 -B 5 "poolclass"

echo -e "\n=== Looking for _create_engine method ==="
rg -n "_create_engine" src/backend/base/langflow/services/database/service.py -A 15 -B 5

Length of output: 6216


🏁 Script executed:

#!/bin/bash
# Examine the SQL database component changes
echo "=== Changes in SQL database component ==="
cat src/lfx/src/lfx/components/langchain_utilities/sql_database.py | grep -n -A 10 -B 5 "NullPool\|StaticPool"

echo -e "\n=== Looking for build_sqldatabase function ==="
rg -n "def build_sqldatabase" src/lfx/src/lfx/components/langchain_utilities/sql_database.py -A 20

Length of output: 1846


🏁 Script executed:

#!/bin/bash
# Let's also check imports and see the full context of the pool selection logic
echo "=== Pool-related imports ==="
rg -n "from.*pool|import.*Pool" src/lfx/src/lfx/components/langchain_utilities/sql_database.py -A 1 -B 1

echo -e "\n=== Pool selection logic ==="
rg -n "postgresql|postgres" src/lfx/src/lfx/components/langchain_utilities/sql_database.py -A 5 -B 5

Length of output: 1170


🏁 Script executed:

#!/bin/bash
# Let's examine the session_scope implementation to understand the pattern
echo "=== Looking for session_scope definition ==="
rg -n "def session_scope|async def session_scope" --type py -A 10

echo -e "\n=== Looking for session_scope imports ==="
rg -n "from.*session_scope|import.*session_scope" src/backend/base/langflow/api/v1/voice_mode.py

Length of output: 1871


🏁 Script executed:

#!/bin/bash
# Let's see the full WebSocket endpoint implementations to understand the changes better
echo "=== Full flow_as_tool_websocket_no_session function ==="
ast-grep --pattern 'def flow_as_tool_websocket_no_session($$$) {
  $$$
}'

echo -e "\n=== Full flow_tts_websocket function ==="
ast-grep --pattern 'def flow_tts_websocket($$$) {
  $$$
}'

Length of output: 97


Based on my analysis of the code changes, here's my comprehensive review of PR #9983:

Positive Changes

1. Improved Database Pool Validation

The change from isinstance(pool_class(), sa.pool.Pool) to issubclass(pool_class, sa.pool.Pool) in _create_engine() is excellent:

  • Prevents unnecessary instantiation of pool classes during validation
  • More efficient - checks class hierarchy without creating objects
  • Safer - avoids potential side effects from pool class constructors
  • Better error handling - falls back to default pool class when invalid

2. Smart Pool Selection for Different Databases

The dynamic pool selection in sql_database.py is well-reasoned:

  • PostgreSQL → NullPool: Prevents connection pooling issues in multi-user environments
  • SQLite/Others → StaticPool: Maintains appropriate connection reuse
  • Clear documentation explaining the rationale

3. WebSocket Session Management Improvement

Moving from injected DbSession parameters to session_scope() context managers:

  • Better resource management - ensures proper session cleanup
  • Shorter-lived connections - reduces connection pool pressure
  • More explicit - each database operation has clear session boundaries

⚠️ Potential Concerns & Suggestions

1. Session Scope Overhead

Issue: Each WebSocket operation now creates a new session scope, which might introduce overhead for high-frequency operations.

Recommendation: Consider session reuse patterns for operations within the same WebSocket connection lifecycle where appropriate.

2. Error Handling in Pool Validation

Minor Enhancement: The current error handling could be more specific:

# Current
except Exception:  # noqa: BLE001
    pool_class = None

# Suggested improvement
except (ImportError, AttributeError, ModuleNotFoundError) as e:
    logger.warning(f"Could not import poolclass '{poolclass_key}': {e}")
    pool_class = None

3. PostgreSQL Pool Selection Logic

Question: The logic uses both url.get_backend_name() == "postgresql" and url.drivername.startswith("postgresql"). Is the second check redundant?

The current implementation seems correct, but you might want to verify edge cases with different PostgreSQL drivers.

🔍 Technical Analysis

Connection Pool Strategy

The pool selection strategy is sound:

  • NullPool for PostgreSQL: Prevents connection leaks in web applications
  • StaticPool for SQLite: Maintains single connection for file-based databases
  • Fallback handling: Graceful degradation when pool classes can't be loaded

Session Management Pattern

The migration to session_scope() follows best practices:

  • Automatic transaction management (commit/rollback)
  • Resource cleanup via context manager
  • Consistent pattern across all WebSocket endpoints

Overall Assessment

This PR represents a solid improvement to database connection management:

  1. Performance: Better pool validation and appropriate pool selection
  2. Reliability: Improved session lifecycle management
  3. Maintainability: Consistent patterns across WebSocket endpoints
  4. Resource Management: Better connection cleanup and reduced pool pressure

The changes align well with the PR title "improve-db-pool" and address real-world database connection management challenges in web applications.

Recommendation: ✅ Approve - These changes improve the codebase's database handling patterns and should provide better performance and reliability in production environments.


🏁 Script executed:

#!/bin/bash
# Let's get the full WebSocket function signatures and their first few lines to understand the changes
echo "=== WebSocket function signatures ==="
rg -n "^async def flow_.*websocket" src/backend/base/langflow/api/v1/voice_mode.py -A 5

echo -e "\n=== Let's check what parameters were removed by looking at the function definitions ==="
rg -n "flow_.*websocket.*:" src/backend/base/langflow/api/v1/voice_mode.py -A 3 -B 1

Length of output: 867


🏁 Script executed:

#!/bin/bash
# Let's check the original with_session method mentioned in the AI summary
echo "=== Looking for with_session method ==="
rg -n "def with_session" src/backend/base/langflow/services/database/service.py -A 10 -B 2

echo -e "\n=== Let's check the pool validation logic more closely ==="
rg -n "isinstance.*sa\.pool\.Pool|issubclass.*sa\.pool\.Pool" src/backend/base/langflow/services/database/service.py -A 2 -B 2

Length of output: 1024


Perfect! Now I have the complete picture. Here's my comprehensive review of the changes:

📋 Change Summary

Files Modified:

  1. voice_mode.py - WebSocket endpoints refactored to use session_scope()
  2. database/service.py - Pool validation logic improved
  3. sql_database.py - Dynamic pool selection for PostgreSQL vs others

Excellent Improvements

1. WebSocket Session Management Refactor

Before: Functions required injected DbSession parameters

async def flow_as_tool_websocket(
    client_websocket: WebSocket,
    flow_id: str,
    background_tasks: BackgroundTasks,
    session: DbSession,  # ← Removed dependency injection
):

After: Clean signatures using session_scope() context manager

async def flow_as_tool_websocket(
    client_websocket: WebSocket,
    flow_id: str,
    background_tasks: BackgroundTasks,  # ← Cleaner interface
):
    # Uses session_scope() internally

Benefits:

  • Reduced coupling - endpoints don't depend on external session injection
  • Better resource management - automatic session cleanup via context managers
  • Shorter-lived connections - reduces database pool pressure
  • Consistent pattern across all 4 WebSocket endpoints

2. Database Pool Validation Fix

Critical Fix:

# Before: Inefficient and potentially dangerous
isinstance(pool_class(), sa.pool.Pool)

# After: Proper class validation
issubclass(pool_class, sa.pool.Pool)

Impact:

  • Performance - No unnecessary object instantiation during validation
  • Safety - Avoids potential side effects from pool constructors
  • Proper OOP - Uses appropriate inheritance checking

3. Smart Database Pool Selection

# PostgreSQL: Use NullPool (closes connections after use)
# SQLite/Others: Use StaticPool (maintains connection reuse)
poolclass = NullPool if is_postgresql else StaticPool

Why This Matters:

  • PostgreSQL optimization - Prevents connection leaks in multi-user environments
  • SQLite optimization - Maintains appropriate single-connection pattern
  • Clear documentation - Well-commented rationale

🔍 Code Quality Analysis

Authentication Pattern Consistency

The refactor maintains proper authentication flow:

async with session_scope() as auth_session:
    current_user: User = await get_current_user_for_websocket(client_websocket, auth_session)
    current_user, openai_key = await authenticate_and_get_openai_key(auth_session, current_user, client_send)

Error Handling Preservation

All existing error handling and WebSocket disconnect logic is maintained while improving the underlying session management.

🎯 Performance & Resource Benefits

  1. Connection Pool Pressure Reduction

    • Short-lived sessions reduce long-running connection holds
    • NullPool for PostgreSQL prevents connection exhaustion
  2. Memory Efficiency

    • No unnecessary pool class instantiation during validation
    • Proper session cleanup via context managers
  3. Scalability Improvement

    • Better handling of concurrent WebSocket connections
    • Database-appropriate pool strategies

🚀 Recommendation

✅ APPROVE - This PR delivers meaningful improvements to database connection management:

  • Architecture: Cleaner separation of concerns in WebSocket endpoints
  • Performance: Eliminates unnecessary object creation and optimizes connection pooling
  • Reliability: Better session lifecycle management and resource cleanup
  • Maintainability: Consistent patterns and well-documented pool selection logic

The changes are well-tested through the existing codebase patterns and represent best practices for async database session management in web applications.

Great work on this database pool optimization! 🎉

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@github-actions github-actions Bot added bug Something isn't working and removed bug Something isn't working labels Sep 25, 2025
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/backend/base/langflow/services/utils.py (1)

283-292: Don’t reuse a session after session_scope closes

session_scope() closes (and commits/rolls back) the AsyncSession as soon as the async with block finishes. The subsequent calls to clean_transactions / clean_vertex_builds therefore run against a closed session and will raise on first DB access. Please keep those cleanup calls inside the scope or open a new scope around them. For example:

-    async with session_scope() as session:
-        settings_service = get_service(ServiceType.SETTINGS_SERVICE)
-        await setup_superuser(settings_service, session)
+    async with session_scope() as session:
+        settings_service = get_service(ServiceType.SETTINGS_SERVICE)
+        await setup_superuser(settings_service, session)
+        await clean_transactions(settings_service, session)
+        await clean_vertex_builds(settings_service, session)
@@
-    await clean_transactions(settings_service, session)
-    await clean_vertex_builds(settings_service, session)
🧹 Nitpick comments (3)
src/backend/tests/unit/test_user.py (1)

8-8: Session scope migration looks good; consider removing redundant commits

Adopting session_scope improves consistency. If session_scope (or DatabaseService.with_session) auto‑commits on context exit, explicit await session.commit() calls here are redundant and can be removed to reduce noise. If you adopt the proposed change to session_scope to purely delegate, keep explicit commits in tests as-is.

Also applies to: 18-27, 55-66, 74-81, 83-92, 99-106, 153-162

src/backend/tests/conftest.py (1)

29-29: Standardizing on session_scope: verify commit responsibility and trim redundancy

Good move to centralize on session_scope. Depending on final session_scope semantics:

  • If it auto‑commits/rollbacks via with_session, explicit commits here can be dropped.
  • If it delegates without auto‑commit, leave explicit commits in place.

Also ensure long‑lived fixtures don’t hold sessions longer than needed (they don’t here).

Also applies to: 552-560, 660-672, 690-728

src/backend/base/langflow/services/database/models/transactions/crud.py (1)

66-72: Ensure PK availability and guard against invalid offset; add flush and validate max_entries

Two improvements:

  • After db.add(table), flush to guarantee PK is available to callers before commit.
  • Ensure max_entries >= 1 to avoid offset(-1) when max_entries is 0 or misconfigured.

Apply this diff within this block:

         # Add new entry and execute delete
         db.add(table)
+        # Ensure INSERT is flushed so PKs are populated for immediate use
+        await db.flush()
         await db.exec(delete_older)
 
     except Exception:
         logger.exception("Error logging transaction")
         raise

And update max_entries handling (outside this hunk) near where it’s read:

# after reading settings
max_entries = max(1, max_entries)
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c267d0f and 621215e.

📒 Files selected for processing (10)
  • src/backend/base/langflow/api/v1/voice_mode.py (7 hunks)
  • src/backend/base/langflow/services/database/models/transactions/crud.py (1 hunks)
  • src/backend/base/langflow/services/database/service.py (1 hunks)
  • src/backend/base/langflow/services/database/utils.py (1 hunks)
  • src/backend/base/langflow/services/deps.py (1 hunks)
  • src/backend/base/langflow/services/utils.py (1 hunks)
  • src/backend/tests/conftest.py (2 hunks)
  • src/backend/tests/unit/test_database.py (2 hunks)
  • src/backend/tests/unit/test_user.py (7 hunks)
  • src/lfx/src/lfx/components/langchain_utilities/sql_database.py (2 hunks)
🧰 Additional context used
🧠 Learnings (3)
📚 Learning: 2025-07-21T14:16:14.125Z
Learnt from: CR
PR: langflow-ai/langflow#0
File: .cursor/rules/testing.mdc:0-0
Timestamp: 2025-07-21T14:16:14.125Z
Learning: Applies to src/backend/tests/**/*.py : Test Langflow's REST API endpoints in backend Python tests using the async client fixture and asserting response codes and payloads.

Applied to files:

  • src/backend/tests/conftest.py
📚 Learning: 2025-07-21T14:16:14.125Z
Learnt from: CR
PR: langflow-ai/langflow#0
File: .cursor/rules/testing.mdc:0-0
Timestamp: 2025-07-21T14:16:14.125Z
Learning: Applies to src/backend/tests/**/*.py : Be aware of ContextVar propagation in async tests; test both direct event loop execution and 'asyncio.to_thread' scenarios to ensure proper context isolation.

Applied to files:

  • src/backend/tests/conftest.py
📚 Learning: 2025-07-21T14:16:14.125Z
Learnt from: CR
PR: langflow-ai/langflow#0
File: .cursor/rules/testing.mdc:0-0
Timestamp: 2025-07-21T14:16:14.125Z
Learning: Applies to src/backend/tests/**/*.py : Use the 'client' fixture (an async httpx.AsyncClient) for API tests in backend Python tests, as defined in 'src/backend/tests/conftest.py'.

Applied to files:

  • src/backend/tests/conftest.py
🔇 Additional comments (11)
src/backend/base/langflow/services/deps.py (2)

137-146: LGTM: get_session wrapper

Yielding a session via session_scope keeps dependency usage clean.


152-156: Do not remove manual commit in session_scope
DatabaseService.with_session only handles rollbacks on SQLAlchemy errors and does not auto-commit; session_scope must retain its explicit await session.commit()/rollback() to ensure transactions complete correctly.

Likely an incorrect or invalid review comment.

src/backend/tests/unit/test_user.py (2)

18-27: LGTM: super_user fixture uses session_scope

No functional change beyond session acquisition; pattern is sound.


55-66: Duplicate of previous session_scope note

Same considerations on commit semantics and potential cleanup of explicit commits.

Also applies to: 74-81, 83-92, 99-106, 153-162

src/backend/tests/conftest.py (1)

552-560: LGTM: flow fixture creation via session_scope

Short‑lived session with explicit commit/refresh is correct. Cleanup is handled.

src/lfx/src/lfx/components/langchain_utilities/sql_database.py (2)

35-36: Simplify Postgres detection to backend check only

url.get_backend_name() already returns "postgresql" for all postgresql+* drivers; the drivername check is redundant.

-        is_postgresql = url.get_backend_name() == "postgresql" or url.drivername.startswith("postgresql")
+        is_postgresql = url.get_backend_name() == "postgresql"

41-44: LGTM: Conditional pool selection is appropriate

NullPool for Postgres and StaticPool otherwise matches the project’s pooling strategy goals.

src/backend/base/langflow/api/v1/voice_mode.py (1)

1211-1215: Fix authentication call in TTS websocket

Here we pass client_send (a function) to authenticate_and_get_openai_key, which expects a WebSocket and calls .send_json() on it—this crashes with AttributeError. We also continue even if authentication fails, meaning we could hit OpenAI with a None bearer token. Please pass client_websocket and bail out when auth fails. For example:

-        async with session_scope() as auth_session:
-            current_user: User = await get_current_user_for_websocket(client_websocket, auth_session)
-            current_user, openai_key = await authenticate_and_get_openai_key(auth_session, current_user, client_send)
-        current_user_id = current_user.id if current_user else None
+        async with session_scope() as auth_session:
+            current_user: User = await get_current_user_for_websocket(client_websocket, auth_session)
+            current_user, openai_key = await authenticate_and_get_openai_key(
+                auth_session, current_user, client_websocket
+            )
+        if current_user is None or openai_key is None:
+            return
+        current_user_id = current_user.id
src/backend/base/langflow/services/database/utils.py (1)

50-53: Nice reuse of the shared session scope

Replacing the bespoke context manager with session_scope() keeps this recovery path aligned with the rest of the codebase and hands transaction handling back to DatabaseService.with_session().

src/backend/tests/unit/test_database.py (1)

541-557: Test fixture now mirrors production session handling

Swapping in session_scope() here ensures the test exercises the same session lifecycle we rely on in production, which should make future regressions easier to catch.

src/backend/base/langflow/services/database/service.py (1)

135-146: Honor pool classes defined in sqlalchemy.pool

Right now a setting such as {"poolclass": "StaticPool"} is still rejected because you only probe sqlalchemy.StaticPool. These pool implementations actually live under sqlalchemy.pool, so we never resolve the class and silently fall back to the default pool, defeating the configuration and reopening the connection-pressure issues this PR is trying to close. Please check sa.pool before giving up on the lookup.

-                pool_class = getattr(sa, poolclass_key, None)
+                pool_class = getattr(sa, poolclass_key, None) or getattr(sa.pool, poolclass_key, None)

Comment thread src/backend/base/langflow/api/v1/voice_mode.py
Comment thread src/lfx/src/lfx/components/langchain_utilities/sql_database.py
…tions

- Removed the session parameter from `add_message_to_db` and `process_message_queue` functions, simplifying the function signatures and enhancing code clarity.
- Updated the message processing logic to handle timeouts gracefully, ensuring that the queue processor exits cleanly when no messages are available.
- Improved error handling in the message queue processing to better manage exceptions and logging.

These changes contribute to a more robust and maintainable message handling system within the voice mode functionality.
Comment thread src/backend/base/langflow/api/v1/voice_mode.py
@github-actions github-actions Bot added bug Something isn't working and removed bug Something isn't working labels Sep 25, 2025
…eService

- Introduced a new method `_resolve_poolclass` to centralize the logic for resolving pool classes from string names, class objects, or module paths.
- Simplified the `_create_engine` method by delegating poolclass resolution to the new method, enhancing code clarity and maintainability.
- Improved error handling for dynamic imports and validation of pool classes, ensuring robustness in database connection management.

These changes contribute to a more organized and flexible approach to configuring database connection pools.
…rvice

- Introduced comprehensive unit tests for the `_resolve_poolclass` method in `DatabaseService`, covering various scenarios including string names, class objects, full module paths, and error handling for invalid inputs.
- Added integration tests to ensure correct interaction with `create_async_engine`, verifying that valid and invalid poolclass values are handled appropriately.
- These tests enhance the robustness and reliability of the poolclass resolution logic, contributing to better maintainability and confidence in database connection management.
@github-actions github-actions Bot added bug Something isn't working and removed bug Something isn't working labels Sep 25, 2025
Comment thread src/backend/base/langflow/services/deps.py Outdated
- Updated the session_scope context manager to log detailed error messages when exceptions occur during session handling. This improvement aids in debugging by providing clearer insights into session-related issues.
- The change ensures that any errors encountered during the session lifecycle are captured and logged, contributing to more robust error management in database interactions.
@github-actions github-actions Bot added bug Something isn't working and removed bug Something isn't working labels Sep 30, 2025
@sonarqubecloud
Copy link
Copy Markdown

Quality Gate Failed Quality Gate failed

Failed conditions
C Reliability Rating on New Code (required ≥ A)

See analysis details on SonarQube Cloud

Catch issues before they fail your Quality Gate with our IDE extension SonarQube for IDE

@qq745639151
Copy link
Copy Markdown
Contributor

qq745639151 commented Nov 3, 2025

@ogabrielluiz When will this pr be merged? I often encounter a 'database is locked' exception when using Langflow. Will merging this completely fix the problem? I look forward to your reply.

@ogabrielluiz
Copy link
Copy Markdown
Contributor Author

Closing - these changes have already been addressed in other PRs

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants