-
Notifications
You must be signed in to change notification settings - Fork 2
Switching strategy #68
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
61191ea
189b872
84680d7
344d325
c55a304
0cbd598
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -128,26 +128,18 @@ def escape_string(self, item): | |||||
| # Strategy cache timeout in seconds (5 minutes) | ||||||
| STRATEGY_CACHE_TIMEOUT = 300 | ||||||
|
|
||||||
| # Global set to track debug-enabled connections | ||||||
| _debug_connections = set() | ||||||
|
|
||||||
| def _strategy_debug_log(message): | ||||||
| """Log strategy debug messages if any connection has debug enabled.""" | ||||||
| if _debug_connections: | ||||||
| print(f"[E6DATA_STRATEGY_DEBUG] {time.strftime('%Y-%m-%d %H:%M:%S')} - {message}") | ||||||
|
|
||||||
|
|
||||||
| def _get_shared_strategy(): | ||||||
| """Get or create the shared strategy storage.""" | ||||||
| global _strategy_manager, _shared_strategy | ||||||
|
|
||||||
| # Try to use multiprocessing.Manager for process-safe storage | ||||||
| try: | ||||||
| if _strategy_manager is None: | ||||||
| _strategy_manager = multiprocessing.Manager() | ||||||
| _shared_strategy = _strategy_manager.dict() | ||||||
| _shared_strategy['active_strategy'] = None | ||||||
| _shared_strategy['last_check_time'] = 0 | ||||||
| _shared_strategy['pending_strategy'] = None | ||||||
| _shared_strategy['query_strategy_map'] = _strategy_manager.dict() | ||||||
| _shared_strategy['last_transition_time'] = 0 | ||||||
| _shared_strategy['session_invalidated'] = False | ||||||
| return _shared_strategy | ||||||
| except: | ||||||
| # Fall back to thread-local storage if Manager fails | ||||||
| return _local_strategy_cache | ||||||
| return _local_strategy_cache | ||||||
|
|
||||||
|
|
||||||
| def _get_active_strategy(): | ||||||
|
|
@@ -175,10 +167,14 @@ def _set_active_strategy(strategy): | |||||
| with _strategy_lock: | ||||||
| shared_strategy = _get_shared_strategy() | ||||||
| current_time = time.time() | ||||||
| old_strategy = shared_strategy.get('active_strategy') | ||||||
|
|
||||||
| # Only update transition time if strategy actually changed | ||||||
| if shared_strategy['active_strategy'] != normalized_strategy: | ||||||
| if old_strategy != normalized_strategy: | ||||||
| shared_strategy['last_transition_time'] = current_time | ||||||
| _strategy_debug_log(f"Setting active strategy: {old_strategy} -> {normalized_strategy}") | ||||||
| else: | ||||||
| _strategy_debug_log(f"Active strategy unchanged: {normalized_strategy}") | ||||||
|
|
||||||
| shared_strategy['active_strategy'] = normalized_strategy | ||||||
| shared_strategy['last_check_time'] = current_time | ||||||
|
|
@@ -188,6 +184,9 @@ def _clear_strategy_cache(): | |||||
| """Clear the cached strategy to force re-detection.""" | ||||||
| with _strategy_lock: | ||||||
| shared_strategy = _get_shared_strategy() | ||||||
| old_strategy = shared_strategy.get('active_strategy') | ||||||
| if old_strategy: | ||||||
| _strategy_debug_log(f"Clearing strategy cache (was: {old_strategy})") | ||||||
| shared_strategy['active_strategy'] = None | ||||||
| shared_strategy['last_check_time'] = 0 | ||||||
| shared_strategy['pending_strategy'] = None | ||||||
|
|
@@ -208,6 +207,8 @@ def _set_pending_strategy(strategy): | |||||
|
|
||||||
| if normalized_strategy != current_active: | ||||||
| shared_strategy['pending_strategy'] = normalized_strategy | ||||||
| query_count = len(shared_strategy.get('query_strategy_map', {})) | ||||||
| _strategy_debug_log(f"Setting pending strategy: {normalized_strategy} (current: {current_active}, active queries: {query_count})") | ||||||
|
|
||||||
|
|
||||||
| def _apply_pending_strategy(): | ||||||
|
|
@@ -219,11 +220,15 @@ def _apply_pending_strategy(): | |||||
| new_strategy = shared_strategy['pending_strategy'] | ||||||
| current_time = time.time() | ||||||
|
|
||||||
| _strategy_debug_log(f"Applying pending strategy: {old_strategy} -> {new_strategy}") | ||||||
|
|
||||||
| shared_strategy['active_strategy'] = new_strategy | ||||||
| shared_strategy['pending_strategy'] = None | ||||||
| shared_strategy['last_check_time'] = current_time | ||||||
| shared_strategy['last_transition_time'] = current_time | ||||||
| shared_strategy['session_invalidated'] = True # Invalidate all sessions | ||||||
|
|
||||||
| _strategy_debug_log(f"Strategy transition complete. All sessions invalidated.") | ||||||
|
|
||||||
| return new_strategy | ||||||
| return None | ||||||
|
|
@@ -250,6 +255,7 @@ def _register_query_strategy(query_id, strategy): | |||||
| query_map = shared_strategy.get('query_strategy_map', {}) | ||||||
| query_map[query_id] = normalized_strategy | ||||||
| shared_strategy['query_strategy_map'] = query_map | ||||||
| _strategy_debug_log(f"Query {query_id} registered with strategy: {normalized_strategy}") | ||||||
|
|
||||||
|
|
||||||
| def _get_query_strategy(query_id): | ||||||
|
|
@@ -271,8 +277,11 @@ def _cleanup_query_strategy(query_id): | |||||
| shared_strategy = _get_shared_strategy() | ||||||
| query_map = shared_strategy.get('query_strategy_map', {}) | ||||||
| if query_id in query_map: | ||||||
| strategy = query_map[query_id] | ||||||
| del query_map[query_id] | ||||||
| shared_strategy['query_strategy_map'] = query_map | ||||||
| remaining_queries = len(query_map) | ||||||
| _strategy_debug_log(f"Query {query_id} completed (was using {strategy}). Remaining active queries: {remaining_queries}") | ||||||
|
|
||||||
|
|
||||||
| def _get_strategy_debug_info(): | ||||||
|
|
@@ -319,6 +328,7 @@ def __init__( | |||||
| auto_resume: bool = True, | ||||||
| scheme: str = 'e6data', | ||||||
| grpc_options: dict = None, | ||||||
| debug: bool = False, | ||||||
| ): | ||||||
| """ | ||||||
| Parameters | ||||||
|
|
@@ -350,6 +360,8 @@ def __init__( | |||||
| - max_send_message_length: Similar to max_receive_message_length, this parameter sets the maximum allowed size (in bytes) for outgoing messages from the gRPC client | ||||||
| - grpc_prepare_timeout: Timeout for prepare statement API call (default to 10 minutes). | ||||||
| - keepalive_time_ms: This parameter defines the time, in milliseconds, Default to 30 seconds | ||||||
| debug: bool, Optional | ||||||
| Flag to enable debug logging for blue-green deployment strategy changes | ||||||
| """ | ||||||
| if not username or not password: | ||||||
| raise ValueError("username or password cannot be empty.") | ||||||
|
|
@@ -379,6 +391,13 @@ def __init__( | |||||
| The default maximum time on client side to wait for the cluster to resume is 5 minutes. | ||||||
| """ | ||||||
| self.grpc_auto_resume_timeout_seconds = self._grpc_options.pop('grpc_auto_resume_timeout_seconds') | ||||||
|
|
||||||
| # Store debug flag and register with debug connections | ||||||
| self._debug = debug | ||||||
| if self._debug: | ||||||
| _debug_connections.add(id(self)) | ||||||
| _strategy_debug_log(f"Debug mode enabled for connection {id(self)}") | ||||||
|
|
||||||
| self._create_client() | ||||||
|
|
||||||
| @property | ||||||
|
|
@@ -505,6 +524,7 @@ def get_session_id(self): | |||||
|
|
||||||
| if active_strategy and not pending_strategy: | ||||||
| # Use cached strategy only if there's no pending strategy | ||||||
| _strategy_debug_log(f"Authenticating with cached strategy: {active_strategy}") | ||||||
| try: | ||||||
| authenticate_response = self._client.authenticate( | ||||||
| authenticate_request, | ||||||
|
|
@@ -518,10 +538,15 @@ def get_session_id(self): | |||||
| new_strategy = authenticate_response.new_strategy.lower() | ||||||
| if new_strategy != active_strategy: | ||||||
| _set_pending_strategy(new_strategy) | ||||||
| # Don't apply immediately - let new queries use fresh connections | ||||||
| _apply_pending_strategy() | ||||||
| self._session_id = None | ||||||
| self.close() | ||||||
| self._create_client() | ||||||
| return self.get_session_id | ||||||
|
||||||
| return self.get_session_id | |
| return self.get_session_id() |
Copilot
AI
Aug 1, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Missing function call parentheses. This should be return self.get_session_id() to actually call the method, not return the method object.
| return self.get_session_id | |
| return self.get_session_id() |
Copilot
AI
Aug 1, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Debug print statement with temporary markers should be removed or replaced with proper logging using the _strategy_debug_log function.
| print(f"@@@@@@ New strategy: {prepare_statement_response.new_strategy}") | |
| _strategy_debug_log(f"New strategy detected: {prepare_statement_response.new_strategy}") |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -12,7 +12,7 @@ | |
|
|
||
| import setuptools | ||
|
|
||
| VERSION = (2, 3, 8,) | ||
| VERSION = (2, 3, 9,) | ||
|
|
||
|
|
||
| def get_long_desc(): | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Comment incorrectly states 'default to True' when the code actually defaults to False. The comment should read '# default to False'.