aminghadersohi commented on code in PR #45845:
URL: https://github.com/apache/superset/pull/45845#discussion_r4429787145


##########
superset/db_engine_specs/impala.py:
##########
@@ -136,30 +139,43 @@ def execute(
     @classmethod
     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
-
-            deadline = time.monotonic() + app.config["SQLLAB_TIMEOUT"]
+        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:
+            # The operation is released before the time limit propagates so
+            # it does not keep running on the coordinator.
             try:
-                while cursor.is_executing():
-                    if time.monotonic() >= deadline:
-                        cursor.cancel_operation()
-                        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)
+                cursor.cancel_operation()
+            except TIME_LIMIT_EXCEPTIONS:
+                raise
+            except Exception:  # pylint: disable=broad-except
+                logger.warning("cancel_operation() failed after a time limit")
+            raise

Review Comment:
   Fixed the remaining polling path in 
24860720185c06394e8eb4ccf5c0f4a30cea21b2. My earlier reply wrongly marked 
handle_cursor (then impala.py:203) unaffected. A signal can interrupt any RPC 
reply, including GetOperationStatus and GetLog, not just FetchResults. Both 
time-limit handlers use one helper to reconnect, cancel, and release 
operation/cursor handles before re-raising; non-time-limit paths are unchanged.
   
   Regression test: 
`test_handle_cursor_reconnects_before_cancelling_an_interrupted_poll` exercises 
status/get_log, SoftTimeLimitExceeded/SupersetTimeoutException, and 
successful/failed cancellation. Before the code change, 
`PYTHONPATH=.:superset-core/src pytest -q 
tests/unit_tests/db_engine_specs/test_impala.py -k interrupted_poll` returned 
`8 failed, 29 deselected`; the assertion was `At index 0 diff: 
call.cancel_operation() != call.reconnect()`. After the change, the Impala/Hive 
suite returned `101 passed`, including that test and 
`test_fetch_data_reconnects_before_cancelling_an_interrupted_fetch`. 
Base/Presto neighbors returned `282 passed`. Staged-file and 
branch-changed-file pre-commit checks passed, including mypy. Real Impala not 
run; no live transport or server-side slot-release claim.
   
   Search: `rg -n 
'cancel_operation|_cancel_operation|SoftTimeLimitExceeded|TIME_LIMIT_EXCEPTIONS|def
 handle_cursor|def fetch_data' superset/db_engine_specs superset/sql_lab.py`, 
plus Spark inheritance.
   
   Siblings checked:
   - superset/db_engine_specs/impala.py:140 — fixed in 
24860720185c06394e8eb4ccf5c0f4a30cea21b2; fetch_data uses the shared 
reconnect-before-cancel helper for time limits during polling or row fetching.
   - superset/db_engine_specs/impala.py:208 — fixed in 
24860720185c06394e8eb4ccf5c0f4a30cea21b2; handle_cursor routes interrupted 
status and log RPCs through the same helper.
   - superset/db_engine_specs/impala.py:167 — fixed in 
24860720185c06394e8eb4ccf5c0f4a30cea21b2; the shared helper reconnects before 
_cancel_operation, preserving reconnect-failure logging and propagation of 
another time limit.
   - superset/db_engine_specs/impala.py:183 — not affected: the low-level 
cancel/release helper is reached through reconnect for signal-driven 
cancellation; ordinary RPC failures are logged, and another time limit 
propagates rather than starting another RPC.
   - superset/db_engine_specs/impala.py:150 — not affected: the monotonic 
deadline is checked after is_executing returns, with no interrupted reply; 
signal exceptions instead enter the reconnect handler.
   - superset/db_engine_specs/impala.py:237 — not affected: explicit Stop is 
checked after status returns, not from a signal interrupt; a time limit during 
cancellation enters the outer reconnect handler.
   - superset/db_engine_specs/impala.py:323 — not affected: cancel_query uses a 
separate HTTP requester, not the interrupted impyla transport.
   - superset/db_engine_specs/base.py:144 — not affected: TIME_LIMIT_EXCEPTIONS 
only defines the exception tuple; it sends no RPC.
   - superset/db_engine_specs/base.py:1624 — not affected: generic fetching 
maps exceptions but issues no cancellation RPC after interruption; Impala wraps 
it with the shared handler.
   - superset/db_engine_specs/base.py:1670 — not affected: pagination entry 
point raises NotImplementedError and sends no RPC.
   - superset/db_engine_specs/base.py:2067 — not affected: default 
handle_cursor is a no-op.
   - superset/db_engine_specs/hive.py:200 — not affected: PyHive fetching has 
no signal-driven cancel follow-up on the interrupted transport.
   - superset/db_engine_specs/hive.py:436 — not affected: explicit Stop calls 
cancel after poll returns; the TIME_LIMIT_EXCEPTIONS handler at line 465 
re-raises without a cancellation RPC.
   - superset/db_engine_specs/spark.py:51 — not affected: inherits Hive 
handling, which re-raises time limits without following them with cancellation 
on the interrupted transport.
   - superset/sql_lab.py:375 — not affected: marks the query timed out and 
raises an application error; it does not send a cancellation RPC on the 
interrupted transport.
   - superset/db_engine_specs/crate.py:99 — not affected: post-processes 
generic fetch results without a time-limit cancel handler.
   - superset/db_engine_specs/exasol.py:165 — not affected: converts generic 
fetch rows without a time-limit cancel handler.
   - superset/db_engine_specs/elasticsearch.py:274 — not affected: HTTP cursor 
pagination, not impyla signal-driven cancellation.
   - superset/db_engine_specs/elasticsearch.py:392 — not affected: OpenDistro 
HTTP cursor pagination, not impyla signal-driven cancellation.
   - superset/db_engine_specs/mssql.py:194 — not affected: converts ODBC rows 
without a time-limit cancel handler.
   - superset/db_engine_specs/bigquery.py:416 — not affected: progressive 
fetching has no cancellation RPC after an interrupted reply.
   - superset/db_engine_specs/datastore.py:319 — not affected: converts fetched 
rows without a time-limit cancel handler.
   - superset/db_engine_specs/ocient.py:322 — not affected: fetch failure 
removes an in-memory mapping and re-raises, without cancellation.
   - superset/db_engine_specs/ocient.py:383 — not affected: records the query 
identifier then delegates to the no-op base handle_cursor.
   - superset/db_engine_specs/drill.py:187 — not affected: handles an 
empty-result RuntimeError without issuing cancellation.
   - superset/db_engine_specs/trino.py:331 — not affected: Trino cursor 
handling does not use impyla or cancel in a signal-exception handler.
   - superset/db_engine_specs/presto.py:1415 — not affected: explicit Stop 
cancellation follows a completed poll, not an interrupted reply.
   



-- 
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]

Reply via email to