From 65e8587e0575793b9594a81bc8338868583c1df9 Mon Sep 17 00:00:00 2001 From: samikshya-chand_data Date: Wed, 4 Feb 2026 13:17:45 +0530 Subject: [PATCH 1/8] Fix 60 seconds delay in gov cloud connections --- src/databricks/sql/auth/retry.py | 9 +++ .../sql/common/unified_http_client.py | 14 ++-- tests/unit/test_retry.py | 20 ++++++ tests/unit/test_unified_http_client.py | 64 +++++++++++++++++++ 4 files changed, 102 insertions(+), 5 deletions(-) diff --git a/src/databricks/sql/auth/retry.py b/src/databricks/sql/auth/retry.py index 4281883da..a49599369 100755 --- a/src/databricks/sql/auth/retry.py +++ b/src/databricks/sql/auth/retry.py @@ -36,6 +36,7 @@ class CommandType(Enum): CLOSE_SESSION = "CloseSession" CLOSE_OPERATION = "CloseOperation" GET_OPERATION_STATUS = "GetOperationStatus" + FEATURE_FLAGS = "FeatureFlags" OTHER = "Other" @classmethod @@ -408,6 +409,14 @@ def should_retry(self, method: str, status_code: int) -> Tuple[bool, str]: "CloseOperation received 404 code from Databricks. Cursor is already closed." ) + # Request failed with 404 for feature flags endpoint (not available in Gov Cloud) + # Feature flags are optional, so gracefully degrade without retrying + if status_code == 404 and self.command_type == CommandType.FEATURE_FLAGS: + return ( + False, + "FeatureFlags endpoint returned 404. Feature flags are optional and will be disabled." + ) + # Request failed, was an ExecuteStatement and the command may have reached the server if ( self.command_type == CommandType.EXECUTE_STATEMENT diff --git a/src/databricks/sql/common/unified_http_client.py b/src/databricks/sql/common/unified_http_client.py index d5f7d3c8d..c04f48b7e 100644 --- a/src/databricks/sql/common/unified_http_client.py +++ b/src/databricks/sql/common/unified_http_client.py @@ -251,11 +251,15 @@ def _prepare_headers( return request_headers - def _prepare_retry_policy(self): + def _prepare_retry_policy(self, url: str = ""): """Set up the retry policy for the current request.""" if isinstance(self._retry_policy, DatabricksRetryPolicy): - # Set command type for HTTP requests to OTHER (not database commands) - self._retry_policy.command_type = CommandType.OTHER + # Detect feature flags endpoint by URL pattern + if "/connector-service/feature-flags/" in url: + self._retry_policy.command_type = CommandType.FEATURE_FLAGS + else: + # Set command type for HTTP requests to OTHER (not database commands) + self._retry_policy.command_type = CommandType.OTHER # Start the retry timer for duration-based retry limits self._retry_policy.start_retry_timer() @@ -285,8 +289,8 @@ def request_context( request_headers = self._prepare_headers(headers) - # Prepare retry policy for this request - self._prepare_retry_policy() + # Prepare retry policy for this request (pass url for detection) + self._prepare_retry_policy(url) # Select appropriate pool manager based on target URL pool_manager = self._get_pool_manager_for_url(url) diff --git a/tests/unit/test_retry.py b/tests/unit/test_retry.py index 897a1d111..dacdf5622 100644 --- a/tests/unit/test_retry.py +++ b/tests/unit/test_retry.py @@ -83,3 +83,23 @@ def test_excessive_retry_attempts_error(self, t_mock, retry_policy): retry_policy.sleep(HTTPResponse(status=503)) # Internally urllib3 calls the increment function generating a new instance for every retry retry_policy = retry_policy.increment() + + def test_feature_flags_404_does_not_retry(self, retry_policy): + """Test that FEATURE_FLAGS CommandType with 404 should not retry""" + retry_policy._retry_start_time = time.time() + retry_policy.command_type = CommandType.FEATURE_FLAGS + + should_retry, msg = retry_policy.should_retry("POST", 404) + + assert should_retry is False + assert "FeatureFlags endpoint returned 404" in msg + assert "optional" in msg + + def test_feature_flags_503_does_retry(self, retry_policy): + """Test that FEATURE_FLAGS CommandType with 503 should retry normally""" + retry_policy._retry_start_time = time.time() + retry_policy.command_type = CommandType.FEATURE_FLAGS + + should_retry, msg = retry_policy.should_retry("POST", 503) + + assert should_retry is True diff --git a/tests/unit/test_unified_http_client.py b/tests/unit/test_unified_http_client.py index 4e9ce1bbf..4433d4e49 100644 --- a/tests/unit/test_unified_http_client.py +++ b/tests/unit/test_unified_http_client.py @@ -12,6 +12,7 @@ from databricks.sql.exc import RequestError from databricks.sql.auth.common import ClientContext from databricks.sql.types import SSLOptions +from databricks.sql.auth.retry import CommandType class TestUnifiedHttpClientMaxRetryError: @@ -134,3 +135,66 @@ def test_generic_exception_no_crash(self, http_client): error = exc_info.value assert "HTTP request error" in str(error) + + +class TestUnifiedHttpClientFeatureFlagsDetection: + """Test feature flags URL detection and CommandType setting.""" + + @pytest.fixture + def client_context(self): + """Create a minimal ClientContext for testing.""" + context = Mock(spec=ClientContext) + context.hostname = "https://test.databricks.com" + context.ssl_options = SSLOptions( + tls_verify=True, + tls_verify_hostname=True, + tls_trusted_ca_file=None, + tls_client_cert_file=None, + tls_client_cert_key_file=None, + tls_client_cert_key_password=None, + ) + context.socket_timeout = 30 + context.retry_stop_after_attempts_count = 3 + context.retry_delay_min = 1.0 + context.retry_delay_max = 10.0 + context.retry_stop_after_attempts_duration = 300.0 + context.retry_delay_default = 5.0 + context.retry_dangerous_codes = [] + context.proxy_auth_method = None + context.pool_connections = 10 + context.pool_maxsize = 20 + context.user_agent = "test-agent" + return context + + @pytest.fixture + def http_client(self, client_context): + """Create UnifiedHttpClient instance.""" + return UnifiedHttpClient(client_context) + + def test_feature_flags_url_sets_feature_flags_command_type(self, http_client): + """Test that feature flags URL sets CommandType.FEATURE_FLAGS""" + feature_flags_url = "https://test.databricks.com/connector-service/feature-flags/v1" + + # Call _prepare_retry_policy with feature flags URL + http_client._prepare_retry_policy(feature_flags_url) + + # Verify CommandType is set to FEATURE_FLAGS + assert http_client._retry_policy.command_type == CommandType.FEATURE_FLAGS + + def test_non_feature_flags_url_sets_other_command_type(self, http_client): + """Test that non-feature-flags URLs set CommandType.OTHER""" + normal_url = "https://test.databricks.com/api/2.0/sql/statements" + + # Call _prepare_retry_policy with normal URL + http_client._prepare_retry_policy(normal_url) + + # Verify CommandType is set to OTHER + assert http_client._retry_policy.command_type == CommandType.OTHER + + def test_empty_url_sets_other_command_type(self, http_client): + """Test that empty URL defaults to CommandType.OTHER""" + # Call _prepare_retry_policy with empty URL + http_client._prepare_retry_policy("") + + # Verify CommandType is set to OTHER + assert http_client._retry_policy.command_type == CommandType.OTHER From ca25c61090c1ee73581569c73d152cccc8c989ec Mon Sep 17 00:00:00 2001 From: samikshya-chand_data Date: Wed, 4 Feb 2026 13:29:49 +0530 Subject: [PATCH 2/8] keep it simple :) --- src/databricks/sql/auth/retry.py | 43 ++----------- .../sql/common/unified_http_client.py | 14 ++-- tests/unit/test_retry.py | 24 +++---- tests/unit/test_unified_http_client.py | 64 ------------------- 4 files changed, 20 insertions(+), 125 deletions(-) diff --git a/src/databricks/sql/auth/retry.py b/src/databricks/sql/auth/retry.py index a49599369..b0c2f497d 100755 --- a/src/databricks/sql/auth/retry.py +++ b/src/databricks/sql/auth/retry.py @@ -36,7 +36,6 @@ class CommandType(Enum): CLOSE_SESSION = "CloseSession" CLOSE_OPERATION = "CloseOperation" GET_OPERATION_STATUS = "GetOperationStatus" - FEATURE_FLAGS = "FeatureFlags" OTHER = "Other" @classmethod @@ -374,6 +373,13 @@ def should_retry(self, method: str, status_code: int) -> Tuple[bool, str]: if status_code == 403: return False, "403 codes are not retried" + # Request failed with 404. Don't retry for any command type. + if status_code == 404: + return ( + False, + "Received 404 - NOT_FOUND. The requested resource does not exist.", + ) + # Request failed and server said NotImplemented. This isn't recoverable. Don't retry. if status_code == 501: return False, "Received code 501 from server." @@ -382,41 +388,6 @@ def should_retry(self, method: str, status_code: int) -> Tuple[bool, str]: if not self._is_method_retryable(method): return False, "Only POST requests are retried" - # Request failed with 404 and was a GetOperationStatus. This is not recoverable. Don't retry. - if status_code == 404 and self.command_type == CommandType.GET_OPERATION_STATUS: - return ( - False, - "GetOperationStatus received 404 code from Databricks. Operation was canceled.", - ) - - # Request failed with 404 because CloseSession returns 404 if you repeat the request. - if ( - status_code == 404 - and self.command_type == CommandType.CLOSE_SESSION - and len(self.history) > 0 - ): - raise SessionAlreadyClosedError( - "CloseSession received 404 code from Databricks. Session is already closed." - ) - - # Request failed with 404 because CloseOperation returns 404 if you repeat the request. - if ( - status_code == 404 - and self.command_type == CommandType.CLOSE_OPERATION - and len(self.history) > 0 - ): - raise CursorAlreadyClosedError( - "CloseOperation received 404 code from Databricks. Cursor is already closed." - ) - - # Request failed with 404 for feature flags endpoint (not available in Gov Cloud) - # Feature flags are optional, so gracefully degrade without retrying - if status_code == 404 and self.command_type == CommandType.FEATURE_FLAGS: - return ( - False, - "FeatureFlags endpoint returned 404. Feature flags are optional and will be disabled." - ) - # Request failed, was an ExecuteStatement and the command may have reached the server if ( self.command_type == CommandType.EXECUTE_STATEMENT diff --git a/src/databricks/sql/common/unified_http_client.py b/src/databricks/sql/common/unified_http_client.py index c04f48b7e..d5f7d3c8d 100644 --- a/src/databricks/sql/common/unified_http_client.py +++ b/src/databricks/sql/common/unified_http_client.py @@ -251,15 +251,11 @@ def _prepare_headers( return request_headers - def _prepare_retry_policy(self, url: str = ""): + def _prepare_retry_policy(self): """Set up the retry policy for the current request.""" if isinstance(self._retry_policy, DatabricksRetryPolicy): - # Detect feature flags endpoint by URL pattern - if "/connector-service/feature-flags/" in url: - self._retry_policy.command_type = CommandType.FEATURE_FLAGS - else: - # Set command type for HTTP requests to OTHER (not database commands) - self._retry_policy.command_type = CommandType.OTHER + # Set command type for HTTP requests to OTHER (not database commands) + self._retry_policy.command_type = CommandType.OTHER # Start the retry timer for duration-based retry limits self._retry_policy.start_retry_timer() @@ -289,8 +285,8 @@ def request_context( request_headers = self._prepare_headers(headers) - # Prepare retry policy for this request (pass url for detection) - self._prepare_retry_policy(url) + # Prepare retry policy for this request + self._prepare_retry_policy() # Select appropriate pool manager based on target URL pool_manager = self._get_pool_manager_for_url(url) diff --git a/tests/unit/test_retry.py b/tests/unit/test_retry.py index dacdf5622..0d01d8675 100644 --- a/tests/unit/test_retry.py +++ b/tests/unit/test_retry.py @@ -84,22 +84,14 @@ def test_excessive_retry_attempts_error(self, t_mock, retry_policy): # Internally urllib3 calls the increment function generating a new instance for every retry retry_policy = retry_policy.increment() - def test_feature_flags_404_does_not_retry(self, retry_policy): - """Test that FEATURE_FLAGS CommandType with 404 should not retry""" + def test_404_does_not_retry_for_any_command_type(self, retry_policy): + """Test that 404 never retries for any CommandType""" retry_policy._retry_start_time = time.time() - retry_policy.command_type = CommandType.FEATURE_FLAGS - should_retry, msg = retry_policy.should_retry("POST", 404) + # Test for each CommandType + for command_type in CommandType: + retry_policy.command_type = command_type + should_retry, msg = retry_policy.should_retry("POST", 404) - assert should_retry is False - assert "FeatureFlags endpoint returned 404" in msg - assert "optional" in msg - - def test_feature_flags_503_does_retry(self, retry_policy): - """Test that FEATURE_FLAGS CommandType with 503 should retry normally""" - retry_policy._retry_start_time = time.time() - retry_policy.command_type = CommandType.FEATURE_FLAGS - - should_retry, msg = retry_policy.should_retry("POST", 503) - - assert should_retry is True + assert should_retry is False, f"404 should not retry for {command_type}" + assert "404" in msg or "NOT_FOUND" in msg diff --git a/tests/unit/test_unified_http_client.py b/tests/unit/test_unified_http_client.py index 4433d4e49..4e9ce1bbf 100644 --- a/tests/unit/test_unified_http_client.py +++ b/tests/unit/test_unified_http_client.py @@ -12,7 +12,6 @@ from databricks.sql.exc import RequestError from databricks.sql.auth.common import ClientContext from databricks.sql.types import SSLOptions -from databricks.sql.auth.retry import CommandType class TestUnifiedHttpClientMaxRetryError: @@ -135,66 +134,3 @@ def test_generic_exception_no_crash(self, http_client): error = exc_info.value assert "HTTP request error" in str(error) - - -class TestUnifiedHttpClientFeatureFlagsDetection: - """Test feature flags URL detection and CommandType setting.""" - - @pytest.fixture - def client_context(self): - """Create a minimal ClientContext for testing.""" - context = Mock(spec=ClientContext) - context.hostname = "https://test.databricks.com" - context.ssl_options = SSLOptions( - tls_verify=True, - tls_verify_hostname=True, - tls_trusted_ca_file=None, - tls_client_cert_file=None, - tls_client_cert_key_file=None, - tls_client_cert_key_password=None, - ) - context.socket_timeout = 30 - context.retry_stop_after_attempts_count = 3 - context.retry_delay_min = 1.0 - context.retry_delay_max = 10.0 - context.retry_stop_after_attempts_duration = 300.0 - context.retry_delay_default = 5.0 - context.retry_dangerous_codes = [] - context.proxy_auth_method = None - context.pool_connections = 10 - context.pool_maxsize = 20 - context.user_agent = "test-agent" - return context - - @pytest.fixture - def http_client(self, client_context): - """Create UnifiedHttpClient instance.""" - return UnifiedHttpClient(client_context) - - def test_feature_flags_url_sets_feature_flags_command_type(self, http_client): - """Test that feature flags URL sets CommandType.FEATURE_FLAGS""" - feature_flags_url = "https://test.databricks.com/connector-service/feature-flags/v1" - - # Call _prepare_retry_policy with feature flags URL - http_client._prepare_retry_policy(feature_flags_url) - - # Verify CommandType is set to FEATURE_FLAGS - assert http_client._retry_policy.command_type == CommandType.FEATURE_FLAGS - - def test_non_feature_flags_url_sets_other_command_type(self, http_client): - """Test that non-feature-flags URLs set CommandType.OTHER""" - normal_url = "https://test.databricks.com/api/2.0/sql/statements" - - # Call _prepare_retry_policy with normal URL - http_client._prepare_retry_policy(normal_url) - - # Verify CommandType is set to OTHER - assert http_client._retry_policy.command_type == CommandType.OTHER - - def test_empty_url_sets_other_command_type(self, http_client): - """Test that empty URL defaults to CommandType.OTHER""" - # Call _prepare_retry_policy with empty URL - http_client._prepare_retry_policy("") - - # Verify CommandType is set to OTHER - assert http_client._retry_policy.command_type == CommandType.OTHER From 616f5b2573d4b7534ff313c799de52e3984ce068 Mon Sep 17 00:00:00 2001 From: samikshya-chand_data Date: Wed, 4 Feb 2026 13:40:47 +0530 Subject: [PATCH 3/8] Add fix for krb error --- .github/workflows/code-coverage.yml | 4 ++++ .github/workflows/code-quality-checks.yml | 4 ++++ .github/workflows/daily-telemetry-e2e.yml | 4 ++++ .github/workflows/integration.yml | 4 ++++ 4 files changed, 16 insertions(+) diff --git a/.github/workflows/code-coverage.yml b/.github/workflows/code-coverage.yml index 3c76be728..122c7144c 100644 --- a/.github/workflows/code-coverage.yml +++ b/.github/workflows/code-coverage.yml @@ -58,6 +58,10 @@ jobs: #---------------------------------------------- # install your root project, if required #---------------------------------------------- + - name: Install Kerberos system dependencies + run: | + sudo apt-get update + sudo apt-get install -y libkrb5-dev - name: Install library run: poetry install --no-interaction --all-extras #---------------------------------------------- diff --git a/.github/workflows/code-quality-checks.yml b/.github/workflows/code-quality-checks.yml index 3c368abef..7d3bf1b52 100644 --- a/.github/workflows/code-quality-checks.yml +++ b/.github/workflows/code-quality-checks.yml @@ -140,6 +140,10 @@ jobs: #---------------------------------------------- # install your root project, if required #---------------------------------------------- + - name: Install Kerberos system dependencies + run: | + sudo apt-get update + sudo apt-get install -y libkrb5-dev - name: Install library run: poetry install --no-interaction --all-extras #---------------------------------------------- diff --git a/.github/workflows/daily-telemetry-e2e.yml b/.github/workflows/daily-telemetry-e2e.yml index 3d61cf177..25b93db21 100644 --- a/.github/workflows/daily-telemetry-e2e.yml +++ b/.github/workflows/daily-telemetry-e2e.yml @@ -60,6 +60,10 @@ jobs: #---------------------------------------------- # install dependencies if cache does not exist #---------------------------------------------- + - name: Install Kerberos system dependencies + run: | + sudo apt-get update + sudo apt-get install -y libkrb5-dev - name: Install dependencies run: poetry install --no-interaction --all-extras diff --git a/.github/workflows/integration.yml b/.github/workflows/integration.yml index ad5369997..3be4f9256 100644 --- a/.github/workflows/integration.yml +++ b/.github/workflows/integration.yml @@ -49,6 +49,10 @@ jobs: #---------------------------------------------- # install dependencies if cache does not exist #---------------------------------------------- + - name: Install Kerberos system dependencies + run: | + sudo apt-get update + sudo apt-get install -y libkrb5-dev - name: Install dependencies run: poetry install --no-interaction --all-extras #---------------------------------------------- From 0a6b7b05fd13e9c02aa9f1d3a52338986828919f Mon Sep 17 00:00:00 2001 From: samikshya-chand_data Date: Wed, 4 Feb 2026 13:44:54 +0530 Subject: [PATCH 4/8] pin poetry --- .github/workflows/code-coverage.yml | 1 + .github/workflows/code-quality-checks.yml | 4 ++++ .github/workflows/daily-telemetry-e2e.yml | 1 + .github/workflows/integration.yml | 1 + 4 files changed, 7 insertions(+) diff --git a/.github/workflows/code-coverage.yml b/.github/workflows/code-coverage.yml index 122c7144c..9cb68dbc9 100644 --- a/.github/workflows/code-coverage.yml +++ b/.github/workflows/code-coverage.yml @@ -36,6 +36,7 @@ jobs: - name: Install Poetry uses: snok/install-poetry@v1 with: + version: "2.2.1" virtualenvs-create: true virtualenvs-in-project: true installer-parallel: true diff --git a/.github/workflows/code-quality-checks.yml b/.github/workflows/code-quality-checks.yml index 7d3bf1b52..cc3952920 100644 --- a/.github/workflows/code-quality-checks.yml +++ b/.github/workflows/code-quality-checks.yml @@ -35,6 +35,7 @@ jobs: - name: Install Poetry uses: snok/install-poetry@v1 with: + version: "2.2.1" virtualenvs-create: true virtualenvs-in-project: true installer-parallel: true @@ -118,6 +119,7 @@ jobs: - name: Install Poetry uses: snok/install-poetry@v1 with: + version: "2.2.1" virtualenvs-create: true virtualenvs-in-project: true installer-parallel: true @@ -195,6 +197,7 @@ jobs: - name: Install Poetry uses: snok/install-poetry@v1 with: + version: "2.2.1" virtualenvs-create: true virtualenvs-in-project: true installer-parallel: true @@ -247,6 +250,7 @@ jobs: - name: Install Poetry uses: snok/install-poetry@v1 with: + version: "2.2.1" virtualenvs-create: true virtualenvs-in-project: true installer-parallel: true diff --git a/.github/workflows/daily-telemetry-e2e.yml b/.github/workflows/daily-telemetry-e2e.yml index 25b93db21..d60b7f5a9 100644 --- a/.github/workflows/daily-telemetry-e2e.yml +++ b/.github/workflows/daily-telemetry-e2e.yml @@ -43,6 +43,7 @@ jobs: - name: Install Poetry uses: snok/install-poetry@v1 with: + version: "2.2.1" virtualenvs-create: true virtualenvs-in-project: true installer-parallel: true diff --git a/.github/workflows/integration.yml b/.github/workflows/integration.yml index 3be4f9256..7fd6d98f1 100644 --- a/.github/workflows/integration.yml +++ b/.github/workflows/integration.yml @@ -33,6 +33,7 @@ jobs: - name: Install Poetry uses: snok/install-poetry@v1 with: + version: "2.2.1" virtualenvs-create: true virtualenvs-in-project: true installer-parallel: true From 9f8d98f0bff7d7d9d1dbcb4321a4a41d9222c2f2 Mon Sep 17 00:00:00 2001 From: samikshya-chand_data Date: Wed, 4 Feb 2026 13:46:52 +0530 Subject: [PATCH 5/8] Pin for publish flow too --- .github/workflows/publish-manual.yml | 1 + .github/workflows/publish-test.yml | 1 + .github/workflows/publish.yml | 1 + 3 files changed, 3 insertions(+) diff --git a/.github/workflows/publish-manual.yml b/.github/workflows/publish-manual.yml index ecad71a29..18d1aa33a 100644 --- a/.github/workflows/publish-manual.yml +++ b/.github/workflows/publish-manual.yml @@ -31,6 +31,7 @@ jobs: - name: Install Poetry uses: snok/install-poetry@v1 # Install Poetry, the Python package manager with: + version: "2.2.1" virtualenvs-create: true virtualenvs-in-project: true installer-parallel: true diff --git a/.github/workflows/publish-test.yml b/.github/workflows/publish-test.yml index 2e6359a78..b7ffee9f4 100644 --- a/.github/workflows/publish-test.yml +++ b/.github/workflows/publish-test.yml @@ -21,6 +21,7 @@ jobs: - name: Install Poetry uses: snok/install-poetry@v1 with: + version: "2.2.1" virtualenvs-create: true virtualenvs-in-project: true installer-parallel: true diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index dde6cc2dc..c592756b8 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -23,6 +23,7 @@ jobs: - name: Install Poetry uses: snok/install-poetry@v1 with: + version: "2.2.1" virtualenvs-create: true virtualenvs-in-project: true installer-parallel: true From 44b09b131d60a2da94b0151d539b4b63821cccf2 Mon Sep 17 00:00:00 2001 From: samikshya-chand_data Date: Wed, 4 Feb 2026 17:19:46 +0530 Subject: [PATCH 6/8] Fix failing tests --- .github/workflows/publish-manual.yml | 8 +++++++ .github/workflows/publish-test.yml | 4 ++++ .github/workflows/publish.yml | 4 ++++ tests/e2e/common/retry_test_mixins.py | 26 +++++++++------------ tests/e2e/common/staging_ingestion_tests.py | 2 +- tests/e2e/common/uc_volume_tests.py | 2 +- 6 files changed, 29 insertions(+), 17 deletions(-) diff --git a/.github/workflows/publish-manual.yml b/.github/workflows/publish-manual.yml index 18d1aa33a..2f2a7a4dd 100644 --- a/.github/workflows/publish-manual.yml +++ b/.github/workflows/publish-manual.yml @@ -36,6 +36,14 @@ jobs: virtualenvs-in-project: true installer-parallel: true + #---------------------------------------------- + # Step 3.5: Install Kerberos system dependencies + #---------------------------------------------- + - name: Install Kerberos system dependencies + run: | + sudo apt-get update + sudo apt-get install -y libkrb5-dev + # #---------------------------------------------- # # Step 4: Load cached virtual environment (if available) # #---------------------------------------------- diff --git a/.github/workflows/publish-test.yml b/.github/workflows/publish-test.yml index b7ffee9f4..023023676 100644 --- a/.github/workflows/publish-test.yml +++ b/.github/workflows/publish-test.yml @@ -37,6 +37,10 @@ jobs: #---------------------------------------------- # install dependencies if cache does not exist #---------------------------------------------- + - name: Install Kerberos system dependencies + run: | + sudo apt-get update + sudo apt-get install -y libkrb5-dev - name: Install dependencies if: steps.cached-poetry-dependencies.outputs.cache-hit != 'true' run: poetry install --no-interaction --no-root diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index c592756b8..4f6dd388b 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -39,6 +39,10 @@ jobs: #---------------------------------------------- # install dependencies if cache does not exist #---------------------------------------------- + - name: Install Kerberos system dependencies + run: | + sudo apt-get update + sudo apt-get install -y libkrb5-dev - name: Install dependencies if: steps.cached-poetry-dependencies.outputs.cache-hit != 'true' run: poetry install --no-interaction --no-root diff --git a/tests/e2e/common/retry_test_mixins.py b/tests/e2e/common/retry_test_mixins.py index b2350bd98..80822ba47 100755 --- a/tests/e2e/common/retry_test_mixins.py +++ b/tests/e2e/common/retry_test_mixins.py @@ -278,7 +278,7 @@ def test_retry_max_count_not_exceeded(self, mock_send_telemetry, extra_params): THEN the connector issues six request (original plus five retries) before raising an exception """ - with mocked_server_response(status=404) as mock_obj: + with mocked_server_response(status=429, headers={"Retry-After": "0"}) as mock_obj: with pytest.raises(MaxRetryError) as cm: extra_params = {**extra_params, **self._retry_policy} with self.connection(extra_params=extra_params) as conn: @@ -467,22 +467,21 @@ def test_retry_safe_execute_statement_retry_condition(self, extra_params): ) def test_retry_abort_close_session_on_404(self, extra_params, caplog): """GIVEN the connector sends a CloseSession command - WHEN server sends a 404 (which is normally retried) - THEN nothing is retried because 404 means the session already closed + WHEN server sends a 404 (which is not retried since commit 41b28159) + THEN nothing is retried because 404 is globally non-retryable """ - # First response is a Bad Gateway -> Result is the command actually goes through - # Second response is a 404 because the session is no longer found + # With the idempotency-based retry refactor, 404 is now globally non-retryable + # regardless of command type. The close() method catches RequestError and proceeds. responses = [ - {"status": 502, "headers": {"Retry-After": "1"}, "redirect_location": None}, {"status": 404, "headers": {}, "redirect_location": None}, ] extra_params = {**extra_params, **self._retry_policy} with self.connection(extra_params=extra_params) as conn: with mock_sequential_server_responses(responses): + # Should not raise an exception, the error is caught internally conn.close() - assert "Session was closed by a prior request" in caplog.text @pytest.mark.parametrize( "extra_params", @@ -493,14 +492,13 @@ def test_retry_abort_close_session_on_404(self, extra_params, caplog): ) def test_retry_abort_close_operation_on_404(self, extra_params, caplog): """GIVEN the connector sends a CancelOperation command - WHEN server sends a 404 (which is normally retried) - THEN nothing is retried because 404 means the operation was already canceled + WHEN server sends a 404 (which is not retried since commit 41b28159) + THEN nothing is retried because 404 is globally non-retryable """ - # First response is a Bad Gateway -> Result is the command actually goes through - # Second response is a 404 because the session is no longer found + # With the idempotency-based retry refactor, 404 is now globally non-retryable + # regardless of command type. The close() method catches RequestError and proceeds. responses = [ - {"status": 502, "headers": {"Retry-After": "1"}, "redirect_location": None}, {"status": 404, "headers": {}, "redirect_location": None}, ] @@ -515,10 +513,8 @@ def test_retry_abort_close_operation_on_404(self, extra_params, caplog): # This call guarantees we have an open cursor at the server curs.execute("SELECT 1") with mock_sequential_server_responses(responses): + # Should not raise an exception, the error is caught internally curs.close() - assert ( - "Operation was canceled by a prior request" in caplog.text - ) @pytest.mark.parametrize( "extra_params", diff --git a/tests/e2e/common/staging_ingestion_tests.py b/tests/e2e/common/staging_ingestion_tests.py index 73aa0a113..a88f55238 100644 --- a/tests/e2e/common/staging_ingestion_tests.py +++ b/tests/e2e/common/staging_ingestion_tests.py @@ -81,7 +81,7 @@ def test_staging_ingestion_life_cycle(self, ingestion_user): # GET after REMOVE should fail with pytest.raises( - Error, match="too many 404 error responses" + Error, match="Staging operation over HTTP was unsuccessful: 404" ): cursor = conn.cursor() query = f"GET 'stage://tmp/{ingestion_user}/tmp/11/16/file1.csv' TO '{new_temp_path}'" diff --git a/tests/e2e/common/uc_volume_tests.py b/tests/e2e/common/uc_volume_tests.py index 93e63bd28..5b4086f91 100644 --- a/tests/e2e/common/uc_volume_tests.py +++ b/tests/e2e/common/uc_volume_tests.py @@ -81,7 +81,7 @@ def test_uc_volume_life_cycle(self, catalog, schema): # GET after REMOVE should fail with pytest.raises( - Error, match="too many 404 error responses" + Error, match="Staging operation over HTTP was unsuccessful: 404" ): cursor = conn.cursor() query = f"GET '/Volumes/{catalog}/{schema}/e2etests/file1.csv' TO '{new_temp_path}'" From eed311bb935c102edabb27cd2961b123270eca03 Mon Sep 17 00:00:00 2001 From: samikshya-chand_data Date: Wed, 4 Feb 2026 17:24:23 +0530 Subject: [PATCH 7/8] Edit order for pypi --- .github/workflows/publish-test.yml | 13 +++++++------ .github/workflows/publish.yml | 13 ++++++++----- 2 files changed, 15 insertions(+), 11 deletions(-) diff --git a/.github/workflows/publish-test.yml b/.github/workflows/publish-test.yml index 023023676..9fb34c1d1 100644 --- a/.github/workflows/publish-test.yml +++ b/.github/workflows/publish-test.yml @@ -59,11 +59,12 @@ jobs: - name: Update pyproject.toml run: poetry version ${{ steps.version.outputs.major-version }}.${{ steps.version.outputs.minor-version }}.dev$(date +%s) #---------------------------------------------- + # Build the package (before publish action) + #---------------------------------------------- + - name: Build package + run: poetry build + #---------------------------------------------- # Attempt push to test-pypi #---------------------------------------------- - - name: Build and publish to pypi - uses: JRubics/poetry-publish@v1.10 - with: - pypi_token: ${{ secrets.TEST_PYPI_TOKEN }} - repository_name: "testpypi" - repository_url: "https://test.pypi.org/legacy/" + - name: Publish to pypi + run: poetry publish --username __token__ --password ${{ secrets.TEST_PYPI_TOKEN }} --repository testpypi --repository-url https://test.pypi.org/legacy/ diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 4f6dd388b..b101f421c 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -61,9 +61,12 @@ jobs: - name: Update pyproject.toml run: poetry version ${{ steps.version.outputs.current-version }} #---------------------------------------------- - # Attempt push to test-pypi + # Build the package (before publish) #---------------------------------------------- - - name: Build and publish to pypi - uses: JRubics/poetry-publish@v1.10 - with: - pypi_token: ${{ secrets.PROD_PYPI_TOKEN }} + - name: Build package + run: poetry build + #---------------------------------------------- + # Publish to pypi + #---------------------------------------------- + - name: Publish to pypi + run: poetry publish --username __token__ --password ${{ secrets.PROD_PYPI_TOKEN }} From b6a417d0281b7dda9d91ae93864f0d402e63c6f5 Mon Sep 17 00:00:00 2001 From: samikshya-chand_data Date: Wed, 4 Feb 2026 17:27:24 +0530 Subject: [PATCH 8/8] One last fix : pls work --- .github/workflows/publish-test.yml | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/.github/workflows/publish-test.yml b/.github/workflows/publish-test.yml index 9fb34c1d1..ea4158934 100644 --- a/.github/workflows/publish-test.yml +++ b/.github/workflows/publish-test.yml @@ -64,7 +64,12 @@ jobs: - name: Build package run: poetry build #---------------------------------------------- + # Configure test-pypi repository + #---------------------------------------------- + - name: Configure test-pypi repository + run: poetry config repositories.testpypi https://test.pypi.org/legacy/ + #---------------------------------------------- # Attempt push to test-pypi #---------------------------------------------- - - name: Publish to pypi - run: poetry publish --username __token__ --password ${{ secrets.TEST_PYPI_TOKEN }} --repository testpypi --repository-url https://test.pypi.org/legacy/ + - name: Publish to test-pypi + run: poetry publish --username __token__ --password ${{ secrets.TEST_PYPI_TOKEN }} --repository testpypi