Back to Langflow

Feature: Windows PostgreSQL Event Loop Fix

docs/features/windows-postgresql-eventloop-fix.md

1.10.0.dev2016.4 KB
Original Source

Feature: Windows PostgreSQL Event Loop Fix

Generated on: 2024-02-13
Status: Approved
Owner: Platform Team / Database Infrastructure


Table of Contents

  1. Overview
  2. Ubiquitous Language Glossary
  3. Domain Model
  4. Behavior Specifications
  5. Architecture Decision Records
  6. Technical Specification
  7. Observability
  8. Deployment & Rollback
  9. Architecture Diagrams

1. Overview

Summary

This feature provides automatic event loop configuration for Windows systems running Langflow with PostgreSQL databases, resolving incompatibility between psycopg (PostgreSQL async driver) and Windows' default ProactorEventLoop.

Business Context

Windows users experience application startup failures when using PostgreSQL as the database backend due to an incompatibility between the psycopg driver and Windows' default event loop implementation. This prevents Windows users from leveraging PostgreSQL's advanced features and scalability, limiting them to SQLite which may not meet enterprise requirements.

Bounded Context

Platform Infrastructure - Database Connectivity Layer

  • Database Service (Conformist): Applies event loop configuration during initialization
  • Application Initialization (Customer-Supplier): Provides early event loop setup
  • Testing Infrastructure (Partnership): Validates cross-platform compatibility

2. Ubiquitous Language Glossary

TermDefinitionCode Reference
Event LoopThe core async execution mechanism in Python that manages and executes asynchronous tasksasyncio.get_event_loop_policy()
ProactorEventLoopWindows' default event loop implementation using I/O Completion Portsasyncio.WindowsProactorEventLoopPolicy
SelectorEventLoopAlternative Windows event loop using select() system call, compatible with psycopgasyncio.WindowsSelectorEventLoopPolicy
psycopgPostgreSQL adapter for Python with async supportpostgresql+psycopg://
Event Loop PolicyStrategy pattern implementation controlling which event loop type is createdasyncio.set_event_loop_policy()
Database URLConnection string specifying database type, credentials, and locationLANGFLOW_DATABASE_URL
Platform DetectionRuntime identification of the operating systemplatform.system()

3. Domain Model

3.1 Aggregates

Platform Configuration Aggregate

  • Root Entity: WindowsPostgresHelper
  • Entities: None (stateless helper)
  • Value Objects:
    • LANGFLOW_DATABASE_URL (constant)
    • POSTGRESQL_PREFIXES (tuple constant)
  • Invariants:
    • Event loop policy must be set before any async database operations
    • Configuration only applies when Windows AND PostgreSQL are detected
    • Configuration is idempotent (safe to call multiple times)

3.2 Domain Events

EventTriggerPayloadConsumers
EventLoopConfiguredWindows + PostgreSQL detected{event_loop: "WindowsSelectorEventLoop", reason: "psycopg_compatibility", source: str}Logger (debug level)
ConfigurationSkippedNon-Windows or non-PostgreSQLNoneNone (silent)

4. Behavior Specifications

Feature: Automatic Event Loop Configuration for Windows PostgreSQL

As a Windows user
I want Langflow to automatically configure the correct event loop
So that I can use PostgreSQL without encountering startup errors

Background

  • Given the application is starting
  • And the platform detection is available

Scenario: Windows with PostgreSQL - Apply Fix

  • Given the operating system is "Windows"
  • And LANGFLOW_DATABASE_URL starts with "postgresql" or "postgres"
  • And the current event loop policy is WindowsProactorEventLoopPolicy
  • When configure_windows_postgres_event_loop() is called
  • Then WindowsSelectorEventLoopPolicy is set as the event loop policy
  • And the function returns True
  • And a debug log is created with context information

Scenario: Windows with PostgreSQL - Already Configured

  • Given the operating system is "Windows"
  • And LANGFLOW_DATABASE_URL starts with "postgresql"
  • And the current event loop policy is already WindowsSelectorEventLoopPolicy
  • When configure_windows_postgres_event_loop() is called
  • Then no changes are made to the event loop policy
  • And the function returns False

Scenario: Windows with SQLite - No Fix Needed

  • Given the operating system is "Windows"
  • And LANGFLOW_DATABASE_URL is "sqlite:///test.db"
  • When configure_windows_postgres_event_loop() is called
  • Then no changes are made to the event loop policy
  • And the function returns False

Scenario: Linux with PostgreSQL - No Fix Needed

  • Given the operating system is "Linux"
  • And LANGFLOW_DATABASE_URL starts with "postgresql"
  • When configure_windows_postgres_event_loop() is called
  • Then no changes are made to the event loop policy
  • And the function returns False

Scenario: Docker Container - No Fix Applied

  • Given the operating system is "Linux" (typical in Docker)
  • And DOCKER_CONTAINER environment variable is set
  • And LANGFLOW_DATABASE_URL starts with "postgresql"
  • When configure_windows_postgres_event_loop() is called
  • Then no changes are made to the event loop policy
  • And the function returns False

Scenario: Missing Database URL

  • Given the operating system is "Windows"
  • And LANGFLOW_DATABASE_URL is not set
  • When configure_windows_postgres_event_loop() is called
  • Then no changes are made to the event loop policy
  • And the function returns False

5. Architecture Decision Records

ADR-001: Centralized Event Loop Configuration Helper

Status: Accepted

Context

The psycopg PostgreSQL driver is incompatible with Windows' default ProactorEventLoop, causing psycopg.InterfaceError during database connection initialization. The fix requires setting WindowsSelectorEventLoopPolicy before any async operations, but this was initially duplicated across multiple entry points.

Decision

Create a centralized helper function configure_windows_postgres_event_loop() that encapsulates all event loop configuration logic, following DRY (Don't Repeat Yourself) and Single Responsibility principles.

Consequences

Benefits:

  • Single source of truth for event loop configuration
  • Easier maintenance and testing
  • Consistent behavior across all entry points
  • Clear separation of concerns

Trade-offs:

  • Additional import required in initialization files
  • Slightly increased module coupling

Impact on Product:

  • Windows users can now use PostgreSQL without configuration changes
  • No impact on Linux/macOS users
  • No performance degradation

ADR-002: Early Configuration at Multiple Entry Points

Status: Accepted

Context

The event loop must be configured before any async operations or database imports. Langflow has multiple entry points: package import, launcher, main module, and service initialization.

Decision

Apply configuration at all critical entry points to ensure coverage regardless of how Langflow is started:

  • __init__.py - Package initialization
  • langflow_launcher.py - CLI launcher
  • __main__.py - Direct module execution
  • DatabaseService.__init__ - Service initialization
  • initialize_services() - Service orchestration

Consequences

Benefits:

  • Guaranteed configuration regardless of entry point
  • Defensive programming approach
  • Idempotent implementation prevents issues from multiple calls

Trade-offs:

  • Configuration may be called multiple times (mitigated by idempotency)
  • Import overhead at package level

Impact on Product:

  • Robust solution that works with all deployment methods
  • No user-visible performance impact

ADR-003: Platform-Specific Event Loop Selection for Uvicorn

Status: Accepted

Context

Uvicorn web server has its own event loop configuration that can override our settings when specified with loop="asyncio" parameter.

Decision

Conditionally set Uvicorn's loop parameter to None (use existing loop) when Windows + PostgreSQL is detected, allowing our pre-configured WindowsSelectorEventLoopPolicy to remain active.

Consequences

Benefits:

  • Preserves our event loop configuration through web server initialization
  • Maintains compatibility with other platforms

Trade-offs:

  • Uvicorn configuration becomes platform-aware
  • Slight deviation from default Uvicorn settings on Windows + PostgreSQL

Impact on Product:

  • Web server starts successfully with PostgreSQL on Windows
  • No impact on other configurations

6. Technical Specification

6.1 Dependencies

TypeNamePurpose
Python ModuleasyncioEvent loop management
Python ModuleplatformOS detection
Python ModuleosEnvironment variable access
LibrarypsycopgPostgreSQL async driver (external)
LibrarysqlalchemyDatabase abstraction layer
ServiceDatabaseServiceDatabase connection management
Loggerlfx.log.loggerStructured logging

6.2 API Contracts

configure_windows_postgres_event_loop(source: str | None = None) -> bool

Purpose: Configures Windows event loop for PostgreSQL compatibility

Parameters:

python
source: str | None  # Optional identifier for logging context (e.g., "main", "launcher")

Response (Success):

python
True  # Event loop was configured

Response (No Action):

python
False  # Configuration not needed or already configured

6.3 Error Handling

Error CodeConditionUser MessageRecovery Action
psycopg.InterfaceErrorProactorEventLoop with psycopg"Psycopg cannot use the 'ProactorEventLoop'"Automatic - helper prevents this error
N/APlatform detection failsSilent - returns FalseNo configuration applied, default behavior
N/AEnvironment variable missingSilent - returns FalseNo configuration applied, uses default

7. Observability

7.1 Key Metrics

MetricTypeDescriptionAlert Threshold
event_loop_configuration_appliedCounterNumber of times configuration was appliedN/A - Informational
event_loop_configuration_skippedCounterNumber of times configuration was skippedN/A - Informational
database_connection_errorsCounterPostgreSQL connection failures> 5 per minute

7.2 Important Logs

Log LevelEventFieldsWhen
DEBUGEvent loop configuredevent_loop, reason, sourceConfiguration applied
INFOPostgreSQL detected on Windowsdatabase_url (sanitized)Service initialization
ERRORDatabase connection failederror_type, platformConnection failure

7.3 Dashboards

  • Platform distribution of database backends
  • Windows PostgreSQL adoption rate
  • Event loop configuration frequency by source

8. Deployment & Rollback

8.1 Feature Flags

FlagPurposeDefaultRollout Strategy
N/AFeature is always active when conditions are metEnabledAutomatic based on platform + database detection

8.2 Database Migrations

  • None required - this is a client-side connection configuration

8.3 Rollback Plan

  1. Revert to previous version of Langflow
  2. Windows + PostgreSQL users must manually set event loop via environment configuration
  3. Or use SQLite as temporary workaround

8.4 Smoke Tests

  • Windows + PostgreSQL: Application starts successfully
  • Windows + PostgreSQL: Database queries execute without errors
  • Windows + SQLite: No event loop changes applied
  • Linux + PostgreSQL: No event loop changes applied
  • macOS + PostgreSQL: No event loop changes applied
  • Docker + PostgreSQL: No event loop changes applied

9. Architecture Diagrams

9.1 Context Diagram (Level 1)

mermaid
C4Context
  title System Context diagram for Windows PostgreSQL Event Loop Fix
  
  Person(dev, "Developer", "Windows user running Langflow")
  System(langflow, "Langflow", "AI application development platform")
  System_Ext(postgres, "PostgreSQL", "Database server")
  System_Ext(sqlite, "SQLite", "File-based database")
  
  Rel(dev, langflow, "Develops AI apps")
  Rel(langflow, postgres, "Stores data (with event loop fix)")
  Rel(langflow, sqlite, "Alternative storage (no fix needed)")

9.2 Container Diagram (Level 2)

mermaid
C4Container
  title Container diagram for Event Loop Configuration
  
  Container(helper, "WindowsPostgresHelper", "Python Module", "Event loop configuration")
  Container(launcher, "Launcher", "Python", "Application entry point")
  Container(dbservice, "DatabaseService", "Python", "Database connection management")
  ContainerDb(postgres, "PostgreSQL", "psycopg", "Async database connection")
  
  Rel(launcher, helper, "Calls configure_windows_postgres_event_loop()")
  Rel(dbservice, helper, "Calls configure_windows_postgres_event_loop()")
  Rel(helper, postgres, "Configures compatible event loop")
  Rel(dbservice, postgres, "Establishes connection")

9.3 Component Diagram (Level 3)

mermaid
graph TB
    subgraph "Initialization Flow"
        A[Application Start] --> B{Platform Check}
        B -->|Windows| C{Database Check}
        B -->|Linux/Mac| D[Skip Configuration]
        C -->|PostgreSQL| E{Event Loop Check}
        C -->|Other DB| D
        E -->|ProactorEventLoop| F[Set SelectorEventLoop]
        E -->|Already Selector| G[Skip - Already Set]
        F --> H[Log Configuration]
        G --> I[Return False]
        H --> J[Return True]
        D --> I
    end
    
    subgraph "Entry Points"
        K[__init__.py] --> A
        L[launcher.py] --> A
        M[__main__.py] --> A
        N[DatabaseService] --> A
        O[initialize_services] --> A
    end

Testing Coverage

Unit Tests (test_windows_postgres_helper.py)

  • ✅ Platform detection (Windows, Linux, macOS, FreeBSD)
  • ✅ Database URL detection (PostgreSQL, postgres://, SQLite, MySQL)
  • ✅ Event loop policy verification
  • ✅ Idempotency testing
  • ✅ Logging context validation
  • ✅ Docker environment compatibility

Integration Tests (test_database_windows_postgres_integration.py)

  • ✅ DatabaseService initialization with various configurations
  • ✅ Cross-platform database URL sanitization
  • ✅ Async operation compatibility
  • ✅ Service-level event loop configuration

Migration Guide for Existing Users

For Windows + PostgreSQL Users

No action required. The fix is automatically applied when:

  1. Operating system is Windows
  2. LANGFLOW_DATABASE_URL starts with postgresql:// or postgres://

For Other Configurations

No changes or impact. The fix only activates for Windows + PostgreSQL combinations.

Environment Variables

Ensure LANGFLOW_DATABASE_URL is properly set in your .env file:

env
LANGFLOW_DATABASE_URL=postgresql://user:password@localhost:5432/langflow

Troubleshooting

Issue: Still Getting ProactorEventLoop Errors

Symptoms: psycopg.InterfaceError: Psycopg cannot use the 'ProactorEventLoop'

Solutions:

  1. Ensure you're using the latest version with this fix
  2. Check that LANGFLOW_DATABASE_URL is properly set before application start
  3. Verify no other code is resetting the event loop policy

Issue: Performance Degradation on Windows

Symptoms: Slower async operations on Windows after the fix

Context: SelectorEventLoop may have different performance characteristics than ProactorEventLoop

Solutions:

  1. This is a necessary trade-off for PostgreSQL compatibility
  2. Consider using connection pooling to minimize impact
  3. For maximum performance with PostgreSQL, consider using WSL2 or Linux

References