Skip to content
Open
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
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,10 @@ instance/
# Scrapy stuff:
.scrapy

# AI Scratch work
/scratch
scratch/

# Sphinx documentation
docs/_build/

Expand Down
2 changes: 1 addition & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ src/

### ORM Model Ownership

All `table=True` SQLModel classes live in `lfx.services.database.models` (flat modules per domain: `flow`, `user`, `folder`, `api_key`, `variable`, `file`, `jobs`, `traces`, `message`, `transactions`, `vertex_builds`, etc.; `auth/` and `deployment_provider_account/` are subpackages). The old `langflow.services.database.models.*` paths remain as re-export shims (class identity preserved — both import paths yield the same class objects, so `SQLModel.metadata` registers each table once). CRUD modules, alembic migrations, and the DB service stay in `langflow-base`; `lfx` owns only the model definitions. Shared model helpers live in `lfx.services.database.utils` (string validators) and `lfx.services.database.models.variable` (the variable type constants); the langflow twins re-export them. <!-- pragma: allowlist secret --> `lfx` depends on `sqlmodel` for these models; import them lazily on lfx hot paths. Known seam wart: `lfx.services.database.models.memory_base` lazily imports `langflow.services.memory_base.preprocessing` inside one default-factory path (embedded-only).
All `table=True` SQLModel classes live in `lfx.services.database.models` (flat modules per domain: `flow`, `user`, `folder`, `api_key`, `variable`, `file`, `jobs`, `traces`, `message`, `transactions`, `vertex_builds`, etc.; `auth/` and `deployment_provider_account/` are subpackages). The old `langflow.services.database.models.*` paths remain as re-export shims (class identity preserved — both import paths yield the same class objects, so `SQLModel.metadata` registers each table once). The Tier 1 **DatabaseService** (engine/session/migration mechanism) now lives in `lfx.services.database.service`; `langflow.services.database.service.DatabaseService` is a thin subclass that overrides only its migration-stream identity (version table `alembic_version`, `script_location` → `langflow/alembic`) and adds domain bootstrap (superuser assignment, schema-health). `lfx` also owns its **own** alembic lineage (`lfx.services.database.migrations`, version table `lfx_alembic_version`, execution tables only) so bare `lfx serve` can provision its schema without langflow; drive it with `lfx db upgrade/check/...`. langflow keeps its 82-migration alembic lineage and the CRUD modules. The model classes are the single source of truth, so the two streams can only differ in staleness — caught by `alembic check` per stream. See `src/lfx/PLUGGABLE_SERVICES.md` (two-stream migration model) and `src/lfx/deploy/` (hydration). `lfx` owns the model definitions. Shared model helpers live in `lfx.services.database.utils` (string validators) and `lfx.services.database.models.variable` (the variable type constants); the langflow twins re-export them. <!-- pragma: allowlist secret --> `lfx` depends on `sqlmodel` for these models; import them lazily on lfx hot paths. Known seam wart: `lfx.services.database.models.memory_base` lazily imports `langflow.services.memory_base.preprocessing` inside one default-factory path (embedded-only).

### Service Layer
Backend services in `src/backend/base/langflow/services/`:
Expand Down
1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -301,6 +301,7 @@ directory = "coverage"
target-version = "py310"
exclude = [
"src/backend/base/langflow/alembic/*",
"src/lfx/src/lfx/services/database/migrations/*",
"src/frontend/tests/assets/*",
"src/lfx/src/lfx/_assets/component_index.json",
"docs/**/API-Reference/python-examples/**",
Expand Down
63 changes: 18 additions & 45 deletions src/backend/base/langflow/helpers/windows_postgres_helper.py
Original file line number Diff line number Diff line change
@@ -1,45 +1,18 @@
"""Helper for Windows + PostgreSQL event loop configuration."""

import asyncio
import os
import platform

from lfx.log.logger import logger

LANGFLOW_DATABASE_URL = "LANGFLOW_DATABASE_URL"
POSTGRESQL_PREFIXES = ("postgresql", "postgres")


def configure_windows_postgres_event_loop(source: str | None = None) -> bool:
"""Configure event loop for Windows + PostgreSQL compatibility.

Args:
source: Optional identifier for logging context

Returns:
True if configuration was applied, False otherwise
"""
if platform.system() != "Windows":
return False

db_url = os.environ.get(LANGFLOW_DATABASE_URL, "")
if not db_url or not any(db_url.startswith(prefix) for prefix in POSTGRESQL_PREFIXES):
return False

# Use getattr to safely access the Windows-only class on all platforms
selector_policy = getattr(asyncio, "WindowsSelectorEventLoopPolicy", None)
if selector_policy is None:
return False

current_policy = asyncio.get_event_loop_policy()
if isinstance(current_policy, selector_policy):
return False

asyncio.set_event_loop_policy(selector_policy())

log_context = {"event_loop": "WindowsSelectorEventLoop", "reason": "psycopg_compatibility"}
if source:
log_context["source"] = source

logger.debug("Windows PostgreSQL event loop configured", extra=log_context)
return True
"""Helper for Windows + PostgreSQL event loop configuration.

The implementation moved to ``lfx.utils.windows_postgres_helper`` when the Tier 1
DatabaseService was extracted into lfx. This shim preserves the historical
``langflow.helpers.windows_postgres_helper`` import path.
"""

from lfx.utils.windows_postgres_helper import (
LANGFLOW_DATABASE_URL,
POSTGRESQL_PREFIXES,
configure_windows_postgres_event_loop,
)

__all__ = [
"LANGFLOW_DATABASE_URL",
"POSTGRESQL_PREFIXES",
"configure_windows_postgres_event_loop",
]
Loading
Loading