rebenitez1802 commented on code in PR #45561:
URL: https://github.com/apache/superset/pull/45561#discussion_r4341671580


##########
superset/sql/execution/executor.py:
##########
@@ -680,16 +684,24 @@ def execute(
                 QueryStatus.TIMED_OUT,
                 "Query exceeded the timeout limit",
                 start_time,
+                query=query,
             )
         except SupersetSecurityException as ex:
-            return self._create_error_result(QueryStatus.FAILED, str(ex), 
start_time)
-        except (OAuth2RedirectError, OAuth2Error):
+            return self._create_error_result(
+                QueryStatus.FAILED, str(ex), start_time, query=query
+            )
+        except (OAuth2RedirectError, OAuth2Error) as ex:
             # Let OAuth2 exceptions propagate so callers (MCP, API) can
             # handle them with context-appropriate responses.
+            self._create_error_result(
+                QueryStatus.FAILED, str(ex), start_time, query=query
+            )
             raise
         except Exception as ex:
             error_msg = self.database.db_engine_spec.extract_error_message(ex)
-            return self._create_error_result(QueryStatus.FAILED, error_msg, 
start_time)
+            return self._create_error_result(
+                QueryStatus.FAILED, error_msg, start_time, query=query
+            )

Review Comment:
   This handler also catches failures from `_store_in_cache()` (line 678), 
which runs *after* the success commit while `query` is still set — so a cache 
error (e.g. Redis down) rewrites an already-committed `success` row to 
`failed`. Suggest guarding the cache write like `_get_from_cache` does:
   
   ```python
   if not has_mutation:
       try:
           self._store_in_cache(result, final_sql, opts)
       except Exception:  # pylint: disable=broad-except
           logger.warning("Failed to cache query result", exc_info=True)
   ```
   (or set `query = None` right after the success commit), plus a test.
   



##########
superset/sql/execution/executor.py:
##########
@@ -1008,14 +1021,41 @@ def _create_error_result(
         :param start_time: Start time for calculating execution duration
         :param partial_results: Optional list of StatementResult from 
successful
             statements before the failure
+        :param query: Persisted audit record, if execution reached that stage
         :returns: QueryResult with error status
         """
-        from superset_core.queries.types import QueryResult as QueryResultType
+        from superset_core.queries.types import (
+            QueryResult as QueryResultType,
+            QueryStatus,
+        )
+
+        from superset.sql.execution.utils import commit_query_unless_stopped
+
+        query_id = None
+        if query is not None:
+            try:
+                # Read the persisted identity without loading expired 
attributes.
+                query_id = inspect(query).identity[0]
+                # A failed metadata flush must be rolled back before recording 
failure.
+                if not db.session.is_active:
+                    db.session.rollback()  # pylint: 
disable=consider-using-transaction
+                query.status = status.value
+                query.error_message = error_message
+                query.end_time = now_as_float()
+                if not commit_query_unless_stopped(query):
+                    status = QueryStatus.STOPPED

Review Comment:
   On a False return, `commit_query_unless_stopped()` has already run 
`refresh(query, with_for_update=True)` without committing, so the Query row 
lock stays held until session teardown. All other call sites commit right after 
(`celery_task.py:609`, `sql_lab.py:160/503/759/840`):
   
   ```suggestion
                   if not commit_query_unless_stopped(query):
                       status = QueryStatus.STOPPED
                       error_message = query.error_message
                       # Release the row lock taken by the locking refresh.
                       db.session.commit()  # pylint: 
disable=consider-using-transaction
   ```
   



##########
superset/sql/execution/executor.py:
##########
@@ -1008,14 +1021,41 @@ def _create_error_result(
         :param start_time: Start time for calculating execution duration
         :param partial_results: Optional list of StatementResult from 
successful
             statements before the failure
+        :param query: Persisted audit record, if execution reached that stage
         :returns: QueryResult with error status
         """
-        from superset_core.queries.types import QueryResult as QueryResultType
+        from superset_core.queries.types import (
+            QueryResult as QueryResultType,
+            QueryStatus,
+        )
+
+        from superset.sql.execution.utils import commit_query_unless_stopped
+
+        query_id = None
+        if query is not None:
+            try:
+                # Read the persisted identity without loading expired 
attributes.
+                query_id = inspect(query).identity[0]
+                # A failed metadata flush must be rolled back before recording 
failure.
+                if not db.session.is_active:
+                    db.session.rollback()  # pylint: 
disable=consider-using-transaction
+                query.status = status.value
+                query.error_message = error_message

Review Comment:
   nit: celery/legacy use `query.end_time or now_as_float()` — matching that 
keeps the paths consistent.
   
   ```suggestion
                   query.end_time = query.end_time or now_as_float()
   ```
   



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