aminghadersohi commented on code in PR #45845:
URL: https://github.com/apache/superset/pull/45845#discussion_r4449191425
##########
superset/db_engine_specs/impala.py:
##########
@@ -130,56 +143,289 @@ def execute(
) -> None:
try:
cursor.execute_async(query)
+ except TIME_LIMIT_EXCEPTIONS:
+ raise
except Exception as ex:
raise cls.get_dbapi_mapped_exception(ex) from ex
@classmethod
+ @guard_cursor
def fetch_data(cls, cursor: Any, limit: int | None = None) ->
list[tuple[Any, ...]]:
"""Wait for asynchronous operations using the public cursor API."""
- if callable(getattr(cursor, "execute_async", None)):
- from impala.error import Error
+ try:
+ if callable(getattr(cursor, "execute_async", None)):
+ from impala.error import Error
+
+ deadline = time.monotonic() + app.config["SQLLAB_TIMEOUT"]
+ try:
+ while cursor.is_executing():
+ if time.monotonic() >= deadline:
+ cls._cancel_operation(cursor)
+ raise TimeoutError(
+ "Timed out waiting for the Impala operation"
+ )
+ time.sleep(0.1)
+ if cursor.execution_failed():
+ # Fetching surfaces the driver's detailed asynchronous
error,
+ # including errors on statements that produce no
result set.
+ cursor.fetchall()
+ except Error as ex:
+ raise cls.get_dbapi_mapped_exception(ex) from ex
+ return super().fetch_data(cursor, limit)
+ except TIME_LIMIT_EXCEPTIONS:
+ cls._cancel_operation_on_time_limit(cursor)
+ raise
Review Comment:
Fixed in 1cb704263a5b816912fa7b562f84b857ad140a38. I took the cancel-only
option: a clean-transport `fetch_data` time limit sends
`cancel_operation(reset_state=False)`, then abandons locally through the guard.
It does not send CloseOperation or CloseSession, including from subsequent
cursor finalization/connection release. `handle_cursor` retains full
cancellation/close cleanup.
Regression: `test_fetch_limit_cancels_without_close_rpcs` covers polling and
row-fetch limits, including the soft-limit and TimerTimeout interrupt paths.
With the final tests retained and impala.py restored from
f73c0a47fcf61c8fadf58cfaf5be48767c14f5aa, all 4 cases failed; restoring the
change makes all 4 pass. This negative control and positive run both used
thrift 0.25.0. The accompanying workflow regression also changed from 1 failed
to 1 passed (`5 failed` before / `5 passed` after overall).
Regression command:
```bash
python -m pytest -q tests/unit_tests/db_engine_specs/test_impala.py
tests/unit_tests/scripts/python_unit_transport_test.py -k
'test_fetch_limit_cancels_without_close_rpcs or
test_python_unit_workflow_installs_transport_extras' -m 'not manual and not
llm_compliance'
```
The scoped CI-flags run (Impala/Hive transport and mock suites,
pending-operation tests, Base, Presto, Trino, executor and workflow tests)
reported `1228 passed, 3 xfailed`, exit 0. The real-driver transport files
account for 265 Impala and 66 Hive passes, with zero skipped cases. The
clean-transport transport regression verifies CancelOperation is the last
request after the fetch limit; the handle_cursor cases still verify full
cleanup. Staged-file/branch-file pre-commit and explicit mypy checks each
exited 0.
Remaining trade-off: CancelOperation itself is not bounded by this handler.
The fetch_data docstring and configuration documentation recommend a driver
network timeout or a larger `ALERT_REPORTS_WORKING_TIME_OUT_LAG` for Impala
alerts/reports. No live Impala timing/admission-slot measurement was performed
in this round.
Sibling search: `rg -n 'def
fetch_data|TIME_LIMIT_EXCEPTIONS|_cancel_operation_on_time_limit|cancel_operation\(|close_operation\('
superset/db_engine_specs superset/utils/hive.py superset/sql/execution`, plus
`rg -n 'def handle_cursor|def fetch_data|cursor.cancel|_cancel_requested_query'
superset/db_engine_specs/{hive,presto,trino}.py`; I read each fetch override
and the polling/cleanup paths.
Siblings checked:
- superset/db_engine_specs/impala.py:181 — fixed in 1cb704263a
- superset/db_engine_specs/impala.py:413 — fixed in 1cb704263a
- superset/db_engine_specs/impala.py:169 — not affected: the separate local
polling deadline retains its existing cleanup; only the signal/time-limit
handler is shortened as requested.
- superset/db_engine_specs/impala.py:383 — not affected: full cleanup
remains available for execution-status polling and explicit Stop.
- superset/db_engine_specs/impala.py:397 — not affected: an interrupted
cleanup RPC abandons locally and is not retried.
- superset/db_engine_specs/impala.py:507 — not affected: handle_cursor
intentionally keeps full cancel/operation/session cleanup.
- superset/db_engine_specs/impala.py:490 — not affected: GetLog limits
propagate to the handle_cursor handler, whose full close is intentionally
retained.
- superset/db_engine_specs/impala.py:146 — not affected: execute re-raises
without adding a fetch cleanup sequence.
- superset/db_engine_specs/impala.py:290 — not affected: transport reset is
local cleanup, not another warehouse cancellation/close RPC.
- superset/db_engine_specs/hive.py:210 — not affected: catches
ProgrammingError only and does not add cancel/close RPCs to a time-limit
handler.
- superset/db_engine_specs/hive.py:493 — not affected: Hive polling cancels
explicit Stop; no equivalent fetch-time multi-RPC cleanup handler.
- superset/db_engine_specs/hive.py:527 — not affected: log time limits only
propagate; no added cancellation/close sequence.
- superset/db_engine_specs/presto.py:1415 — not affected: uses its own
polling/Stop cancellation, inherits Base fetch_data and has no Impala-style
fetch-time cleanup sequence.
- superset/db_engine_specs/trino.py:331 — not affected: uses its own
polling/Stop path, inherits Base fetch_data and has no Impala-style fetch-time
cleanup sequence.
- superset/db_engine_specs/trino.py:406 — not affected: handles explicit
requested cancellation, not fetch time-limit cleanup.
- superset/db_engine_specs/base.py:1632 — not affected: maps fetch errors
without sending cancellation/close RPCs.
- superset/db_engine_specs/base.py:1678 — not affected: abstract
native-pagination entry point, not a time-limit cleanup handler.
- superset/db_engine_specs/base.py:2103 — not affected: delegates to the
engine callback; guard abandonment prevents downstream cleanup RPCs.
- superset/utils/hive.py:90 — not affected: interrupted generated RPCs
abandon locally before driver-internal cleanup; no additional
cancellation/close RPCs are sent.
- superset/sql/execution/executor.py:244 — not affected: truncation probes
delegate to the engine fetch method and re-raise time limits.
- superset/db_engine_specs/bigquery.py:416 — not affected: result
sampling/error fallback has no cancel/close sequence in a time-limit handler.
- superset/db_engine_specs/crate.py:99 — not affected: delegates fetching
and transforms timestamps without time-limit cleanup RPCs.
- superset/db_engine_specs/datastore.py:319 — not affected: delegates
fetching and transforms rows without time-limit cleanup RPCs.
- superset/db_engine_specs/drill.py:187 — not affected: handles a specific
RuntimeError without cancellation/close RPCs.
- superset/db_engine_specs/exasol.py:165 — not affected: delegates fetching
and converts rows without time-limit cleanup RPCs.
- superset/db_engine_specs/mssql.py:194 — not affected: delegates fetching
and converts rows without time-limit cleanup RPCs.
- superset/db_engine_specs/ocient.py:322 — not affected: removes a local
query-ID mapping on error without cancellation/close RPCs.
- superset/db_engine_specs/elasticsearch.py:274 — not affected: separate
native-pagination endpoint, not an Impala fetch-time cancellation handler.
- superset/db_engine_specs/elasticsearch.py:392 — not affected: separate
OpenDistro pagination endpoint, not an Impala fetch-time cancellation handler.
I have not resolved the thread or requested review.
##########
tests/unit_tests/db_engine_specs/test_impala_transport.py:
##########
@@ -0,0 +1,916 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+"""
+Time-limit cancellation over real impyla Thrift transports.
+
+A local HiveServer2 stand-in serves impyla's binary, SASL PLAIN and HTTP
+transports. The time limit is raised right after a reply header is read, as a
+signal landing at that point would, so the rest of the reply is left in the
+client's buffers.
+"""
+
+from __future__ import annotations
+
+import signal
+import socket
+import struct
+import threading
+from collections.abc import Iterator
+from contextlib import closing
+from dataclasses import dataclass, field
+from typing import Any
+from unittest.mock import Mock, patch
+
+import pytest
+from celery.exceptions import SoftTimeLimitExceeded
+
+from superset.constants import QUERY_EARLY_CANCEL_KEY
+from superset.db_engine_specs.impala import ImpalaEngineSpec as spec # noqa:
N813
+from superset.errors import ErrorLevel, SupersetErrorType
+from superset.exceptions import SupersetTimeoutException
+from superset.sql.execution.executor import _LimitedCursor
+
+hs2 = pytest.importorskip("impala.hiveserver2")
+ttypes = pytest.importorskip("impala._thrift_gen.TCLIService.ttypes")
+TCLIService = pytest.importorskip("impala._thrift_gen.TCLIService.TCLIService")
Review Comment:
Fixed in 1cb704263a5b816912fa7b562f84b857ad140a38 using the workflow-install
option. The Python unit-test job installs the hive/impala extras immediately
after its existing backend setup, before pytest:
```bash
uv pip install --system -e ".[hive,impala]"
```
Neither requirements/development.in nor requirements/development.txt changed
(`git diff f73c0a47fcf61c8fadf58cfaf5be48767c14f5aa..HEAD --
requirements/development.in requirements/development.txt` is empty).
Regression: `test_python_unit_workflow_installs_transport_extras` requires
that unconditional install before the unit-test step. Retaining the added test
but restoring the workflow from f73c0a47fcf61c8fadf58cfaf5be48767c14f5aa
produces 1 failure; restoring the change produces 1 pass. It was included in
the regression selection reported as `5 failed` before / `5 passed` after, with
the four cancel-only regression cases.
I installed the same extras locally with `uv pip install --python
/tmp/45845-r9-venv/bin/python -e '.[hive,impala]'` (exit 0). Import metadata
and the loaded module paths confirm impyla 0.24.0, thrift 0.25.0, thrift-sasl
0.4.3 and PyHive 0.7.0 in that environment. The CI-flags scoped pytest run and
its JUnit report show:
| File | Passed | Skipped |
|---|---:|---:|
| test_impala_transport.py | 265 | 0 |
| test_hive_transport.py | 66 | 0 |
| test_impala.py | 68 | 0 |
| test_hive.py | 29 | 0 |
The broader scope including sibling engines, pending-operation, executor and
workflow regressions reported `1228 passed, 3 xfailed`, exit 0.
Staged-file/branch-file pre-commit and explicit mypy checks exited 0. This is
local validation; it is not a claim that the newly triggered GitHub CI run has
finished.
Sibling search: `rg -n 'setup-backend|requirements/development|pytest'
.github/workflows/superset-python-unittest.yml
.github/workflows/python-nightly-canary.yml
.github/actions/setup-backend/action.yml`, and driver `importorskip` sites in
both transport files.
Siblings checked:
- .github/workflows/superset-python-unittest.yml:68 — fixed in 1cb704263a
- tests/unit_tests/db_engine_specs/test_impala_transport.py:49 — fixed in
1cb704263a
- tests/unit_tests/db_engine_specs/test_hive_transport.py:42 — fixed in
1cb704263a
- .github/actions/setup-backend/action.yml:73 — not affected: the shared
development-requirements install is intentionally unchanged; the unit-test job
adds its own optional drivers afterward.
- .github/workflows/python-nightly-canary.yml:48 — not affected: separate
canary job is outside the requested unit-job-only installation change.
- requirements/development.in — not affected: unchanged; no lockfile
recompile in this approach.
- requirements/development.txt — not affected: unchanged; no generated-pin
edits.
I have not resolved the thread or requested review.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]