-
Notifications
You must be signed in to change notification settings - Fork 164
Description
Summary
After merging PR #7699 (GraphQL legacy code restructuring), SQLAlchemy ORM relationship mapper initialization fails with ArgumentError: Could not locate any relevant foreign key columns when starting the http://Backend.AI Manager.
Steps to Reproduce
- Merge PR refactor(BA-3618, BA-3619): Models package refactoring for import isolation #7699 which restructured GraphQL legacy code from models/gql_models/ to api/gql_legacy/
- Start the http://Backend.AI Manager application
- SQLAlchemy attempts to initialize model relationships during startup
- Observe mapper initialization errors
Expected Behavior
All SQLAlchemy ORM relationship mappers should initialize successfully without errors. String-based primaryjoin expressions should correctly resolve referenced classes at runtime.
Actual Behavior
SQLAlchemy mapper initialization fails with errors like:
ArgumentError: Could not locate any relevant foreign key columns for primary join condition 'UserRow.uuid == foreign(VFolderRow.user)' on relationship UserRow.vfolder_rows
The string-based primaryjoin expressions fail to resolve referenced classes because the classes are not available in the runtime namespace when the expressions are evaluated.
Root Cause
Import Path Restructuring Impact:
- PR refactor(BA-3618, BA-3619): Models package refactoring for import isolation #7699 changed import paths in 182 files
- Relative import depth increased from 2 levels (../../) to 3 levels (../../../)
- Module loading order changed due to import path restructuring
- Import isolation strengthened between modules
String-based Primaryjoin Limitation:
- 33 relationship definitions across 17 model files used string-based primaryjoin parameters
- Example: primaryjoin="UserRow.uuid == foreign(VFolderRow.user)"
- SQLAlchemy evaluates these strings at runtime using eval() in the current namespace
- Referenced classes (e.g., UserRow) must be imported and available in the namespace
- After PR refactor(BA-3618, BA-3619): Models package refactoring for import isolation #7699's import isolation changes, referenced classes were no longer in namespace during evaluation
Why It Broke:
The import restructuring created stronger module boundaries. When SQLAlchemy tried to evaluate string expressions like "UserRow.uuid == foreign(VFolderRow.user)" in a module that only imported the immediate dependencies, the referenced UserRow class wasn't available in the evaluation namespace.
Solution
Converted all 33 string-based primaryjoin definitions to callable function-based references with lazy imports
Before (String-based):
user = relationship(
"UserRow",
primaryjoin="UserRow.uuid == foreign(VFolderRow.user)",
)After (Callable function with lazy import):
from sqlalchemy.orm import foreign
def _get_user_join_condition():
from ai.backend.manager.models.user import UserRow
return UserRow.uuid == foreign(VFolderRow.user)
user = relationship(
"UserRow",
primaryjoin=_get_user_join_condition,
)Why This Works:
- Function-based primaryjoin uses lazy evaluation
- Import happens inside the function, executed when relationship is accessed
- Classes are imported at usage time, not at definition time
- Bypasses namespace resolution issues from import isolation
Affected Files (17 files, 33 conversions)
- src/ai/backend/manager/models/container_registry/row.py (2)
- src/ai/backend/manager/models/association_container_registries_groups/row.py (1)
- src/ai/backend/manager/models/group/row.py (3)
- src/ai/backend/manager/models/vfolder/row.py (2)
- src/ai/backend/manager/models/network/row.py (2)
- src/ai/backend/manager/models/notification/row.py (4)
- src/ai/backend/manager/models/user/row.py (4)
- src/ai/backend/manager/models/endpoint/row.py (4)
- src/ai/backend/manager/models/deployment_revision/row.py (3)
- src/ai/backend/manager/models/deployment_policy/row.py (1)
- src/ai/backend/manager/models/deployment_auto_scaling_policy/row.py (1)
- src/ai/backend/manager/models/scaling_group/row.py (1)
- src/ai/backend/manager/models/resource_preset/row.py (1)
- src/ai/backend/manager/models/routing/row.py (1)
- src/ai/backend/manager/models/domain/row.py (1)
- src/ai/backend/manager/models/image/row.py (1)
- src/ai/backend/manager/models/kernel/row.py (1)
JIRA Issue: BA-3793