Skip to content

Commit a391d9d

Browse files
committed
feat: simplify IRIS connection architecture (Feature 051)
Simplify IRIS database connection management from 6 complex components to 1-2 simple modules with production-ready features. ## Changes **Core Implementation:** - New `iris_vector_rag/common/iris_connection.py` - Unified connection module - Single function: `get_iris_connection()` with module-level caching - Automatic edition detection (Community vs Enterprise) - Thread-safe operations with threading.Lock - Preserves UV compatibility fix (Issue #5) - New `iris_vector_rag/common/exceptions.py` - Custom exceptions - ValidationError for parameter validation (fail-fast) - ConnectionLimitError for edition-aware connection limiting **Connection Pooling (User Story 3):** - `IRISConnectionPool` class for high-concurrency scenarios - Edition-aware defaults (Community=1, Enterprise=20) - Thread-safe acquire/release with queue.Queue - Context manager protocol support - Timeout handling for pool exhaustion **Backward Compatibility:** - Added deprecation warnings to 3 legacy modules: - `iris_vector_rag/common/connection_manager.py` - `iris_vector_rag/common/iris_connection_manager.py` - `iris_vector_rag/testing/connection_pool.py` - All warnings include migration guidance to new API **Testing:** - 12 contract tests (100% passing) - 18 integration tests (properly skipped without IRIS) - ZERO breaking changes to existing functionality **Code Quality:** - PEP 8 compliant (black formatting) - Organized imports (isort) - Zero critical flake8 issues ## Migration Old: ```python from iris_vector_rag.common import IRISConnectionManager manager = IRISConnectionManager() conn = manager.get_connection() ``` New: ```python from iris_vector_rag.common import get_iris_connection conn = get_iris_connection() ``` See specs/051-simplify-iris-connection/quickstart.md for details. ## Testing ```bash # Contract tests SKIP_IRIS_CONTAINER=1 pytest tests/contract/test_iris_connection_contract.py -v # Result: 12 passed, 4 skipped in 0.23s # Integration tests (require IRIS database) SKIP_IRIS_CONTAINER=0 pytest tests/integration/test_iris_connection_integration.py -v ``` Closes #051
1 parent 9f09e37 commit a391d9d

File tree

15 files changed

+4091
-28
lines changed

15 files changed

+4091
-28
lines changed

iris_vector_rag/common/connection_manager.py

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,47 @@
11
"""
22
Centralized connection manager for RAG pipelines
33
Handles JDBC, ODBC, and future dbapi connections with a unified interface
4+
5+
DEPRECATED: This module is deprecated as of Feature 051 (Simplify IRIS Connection).
6+
Use iris_vector_rag.common.get_iris_connection() instead for simple connections,
7+
or iris_vector_rag.common.IRISConnectionPool() for pooling.
8+
See specs/051-simplify-iris-connection/quickstart.md for migration guide.
49
"""
510

611
import logging
712
import os
13+
import warnings
814
from contextlib import contextmanager
915
from typing import Any, List, Optional
1016

1117
logger = logging.getLogger(__name__)
1218

1319

1420
class ConnectionManager:
15-
"""Manages database connections for RAG pipelines"""
21+
"""
22+
Manages database connections for RAG pipelines
23+
24+
DEPRECATED: Use get_iris_connection() or IRISConnectionPool instead.
25+
"""
1626

1727
def __init__(self, connection_type: str = "odbc"):
1828
"""
1929
Initialize connection manager
2030
2131
Args:
2232
connection_type: Either "jdbc", "odbc", or "dbapi" (default: "odbc" for stability)
33+
34+
DEPRECATED: This class is deprecated. Use get_iris_connection() instead:
35+
from iris_vector_rag.common import get_iris_connection
36+
conn = get_iris_connection()
2337
"""
38+
warnings.warn(
39+
"ConnectionManager is deprecated as of Feature 051. "
40+
"Use get_iris_connection() for simple connections or IRISConnectionPool for pooling. "
41+
"See specs/051-simplify-iris-connection/quickstart.md for migration guide.",
42+
DeprecationWarning,
43+
stacklevel=2,
44+
)
2445
self.connection_type = connection_type.lower()
2546
self._connection = None
2647
self._cursor = None
@@ -37,7 +58,9 @@ def connect(self):
3758

3859
if self.connection_type == "jdbc":
3960
try:
40-
from iris_vector_rag.common.iris_connection_manager import get_iris_jdbc_connection
61+
from iris_vector_rag.common.iris_connection_manager import (
62+
get_iris_jdbc_connection,
63+
)
4164

4265
self._connection = get_iris_jdbc_connection()
4366
logger.info("Established JDBC connection")
@@ -48,7 +71,9 @@ def connect(self):
4871

4972
elif self.connection_type == "dbapi":
5073
try:
51-
from iris_vector_rag.common.iris_dbapi_connector import get_iris_dbapi_connection
74+
from iris_vector_rag.common.iris_dbapi_connector import (
75+
get_iris_dbapi_connection,
76+
)
5277

5378
self._connection = get_iris_dbapi_connection()
5479
if not self._connection: # If get_iris_dbapi_connection returns None
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
"""
2+
Custom exceptions for IRIS connection management.
3+
4+
This module defines the exception hierarchy for the unified IRIS connection module,
5+
providing clear, actionable error messages for connection failures.
6+
"""
7+
8+
9+
class ValidationError(ValueError):
10+
"""
11+
Raised when connection parameters fail validation before connection attempt.
12+
13+
This exception is raised during parameter validation (before any connection
14+
attempt), providing immediate feedback on invalid configuration.
15+
16+
Attributes:
17+
parameter_name: Name of the parameter that failed validation
18+
invalid_value: The value that was rejected
19+
valid_range: Description of acceptable values
20+
message: Full error message with actionable guidance
21+
22+
Example:
23+
>>> raise ValidationError(
24+
... parameter_name="port",
25+
... invalid_value=99999,
26+
... valid_range="1-65535",
27+
... message="Invalid port 99999: must be between 1-65535"
28+
... )
29+
"""
30+
31+
def __init__(
32+
self, parameter_name: str, invalid_value, valid_range: str, message: str
33+
):
34+
self.parameter_name = parameter_name
35+
self.invalid_value = invalid_value
36+
self.valid_range = valid_range
37+
super().__init__(message)
38+
39+
40+
class ConnectionLimitError(RuntimeError):
41+
"""
42+
Raised when IRIS Community Edition connection limit is reached.
43+
44+
This exception is raised when attempting to create more connections than
45+
allowed by the detected IRIS edition (typically 1 for Community Edition).
46+
47+
Attributes:
48+
current_limit: Maximum connections allowed for detected edition
49+
suggested_actions: List of actionable suggestions for resolving the issue
50+
message: Full error message with context and suggestions
51+
52+
Example:
53+
>>> raise ConnectionLimitError(
54+
... current_limit=1,
55+
... suggested_actions=[
56+
... "Use connection queuing with IRISConnectionPool",
57+
... "Run tests serially with pytest -n 0",
58+
... "Set IRIS_BACKEND_MODE=community explicitly"
59+
... ],
60+
... message="IRIS Community Edition connection limit (1) reached. Consider: ..."
61+
... )
62+
"""
63+
64+
def __init__(self, current_limit: int, suggested_actions: list[str], message: str):
65+
self.current_limit = current_limit
66+
self.suggested_actions = suggested_actions
67+
super().__init__(message)
68+
69+
def __str__(self) -> str:
70+
"""Format error message with suggested actions."""
71+
base_message = super().__str__()
72+
if self.suggested_actions:
73+
actions = "\n - ".join(self.suggested_actions)
74+
return f"{base_message}\n\nSuggested actions:\n - {actions}"
75+
return base_message

0 commit comments

Comments
 (0)