This is an automated email from the ASF dual-hosted git repository.
bbovenzi pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/airflow.git
The following commit(s) were added to refs/heads/main by this push:
new d36cf052d6 Use Task Tries rest API and not viewspy endpoint (#41196)
d36cf052d6 is described below
commit d36cf052d6eb3ce6c73fb2a5dbfba3d99d45cd1a
Author: Brent Bovenzi <[email protected]>
AuthorDate: Thu Aug 1 15:08:55 2024 -0400
Use Task Tries rest API and not viewspy endpoint (#41196)
---
airflow/www/static/js/api/useTIHistory.ts | 46 +++++++++++-----------
airflow/www/static/js/dag/details/gantt/Row.tsx | 8 ++--
.../static/js/dag/details/taskInstance/Details.tsx | 8 ++--
.../dag/details/taskInstance/Logs/index.test.tsx | 38 ++++++++++--------
.../js/dag/details/taskInstance/TrySelector.tsx | 8 ++--
airflow/www/templates/airflow/dag.html | 2 +-
airflow/www/views.py | 35 ----------------
tests/www/views/test_views_ti_history.py | 44 ---------------------
8 files changed, 60 insertions(+), 129 deletions(-)
diff --git a/airflow/www/static/js/api/useTIHistory.ts
b/airflow/www/static/js/api/useTIHistory.ts
index 60e29e351e..0293a39b93 100644
--- a/airflow/www/static/js/api/useTIHistory.ts
+++ b/airflow/www/static/js/api/useTIHistory.ts
@@ -17,48 +17,46 @@
* under the License.
*/
-import axios, { AxiosResponse } from "axios";
-import { useQuery } from "react-query";
+import axios from "axios";
+import { useQuery, UseQueryOptions } from "react-query";
import { useAutoRefresh } from "src/context/autorefresh";
-import type { TaskInstance } from "src/types/api-generated";
+import type {
+ GetTaskInstanceTriesVariables,
+ TaskInstanceCollection,
+} from "src/types/api-generated";
import { getMetaValue } from "src/utils";
-interface Props {
- dagId: string;
- runId: string;
- taskId: string;
+interface Props extends GetTaskInstanceTriesVariables {
mapIndex?: number;
- enabled?: boolean;
+ options?: UseQueryOptions<TaskInstanceCollection>;
}
export default function useTIHistory({
dagId,
- runId,
+ dagRunId,
taskId,
- mapIndex = -1,
- enabled,
+ mapIndex,
+ options,
}: Props) {
const { isRefreshOn } = useAutoRefresh();
- return useQuery(
- ["tiHistory", dagId, runId, taskId, mapIndex],
+ return useQuery<TaskInstanceCollection>(
+ ["tiHistory", dagId, dagRunId, taskId, mapIndex],
() => {
- const tiHistoryUrl = getMetaValue("ti_history_url");
+ const tiHistoryUrl = getMetaValue("task_tries_api")
+ .replace("_DAG_ID_", dagId)
+ .replace("_DAG_RUN_ID_", dagRunId)
+ .replace("_TASK_ID_", taskId);
- const params = {
- dag_id: dagId,
- run_id: runId,
- task_id: taskId,
- map_index: mapIndex,
- };
+ if (mapIndex && mapIndex > -1) {
+ tiHistoryUrl.replace("/tries", `/${mapIndex}/tries`);
+ }
- return axios.get<AxiosResponse, Partial<TaskInstance>[]>(tiHistoryUrl, {
- params,
- });
+ return axios.get(tiHistoryUrl);
},
{
- enabled,
refetchInterval: isRefreshOn && (autoRefreshInterval || 1) * 1000,
+ ...options,
}
);
}
diff --git a/airflow/www/static/js/dag/details/gantt/Row.tsx
b/airflow/www/static/js/dag/details/gantt/Row.tsx
index dfb529c381..c93d1d7fde 100644
--- a/airflow/www/static/js/dag/details/gantt/Row.tsx
+++ b/airflow/www/static/js/dag/details/gantt/Row.tsx
@@ -52,8 +52,10 @@ const Row = ({
const { data: tiHistory } = useTIHistory({
dagId,
taskId: task.id || "",
- runId: runId || "",
- enabled: !!(instance?.tryNumber && instance?.tryNumber > 1) && !!task.id,
// Only try to look up task tries if try number > 1
+ dagRunId: runId || "",
+ options: {
+ enabled: !!(instance?.tryNumber && instance?.tryNumber > 1) &&
!!task.id, // Only try to look up task tries if try number > 1
+ },
});
const isSelected = taskId === instance?.taskId;
@@ -83,7 +85,7 @@ const Row = ({
ganttEndDate={ganttEndDate}
/>
)}
- {(tiHistory || []).map((ti) => (
+ {(tiHistory?.taskInstances || []).map((ti) => (
<InstanceBar
key={`${taskId}-${ti.tryNumber}`}
instance={ti}
diff --git a/airflow/www/static/js/dag/details/taskInstance/Details.tsx
b/airflow/www/static/js/dag/details/taskInstance/Details.tsx
index dfd2a921d3..d5bb4210d2 100644
--- a/airflow/www/static/js/dag/details/taskInstance/Details.tsx
+++ b/airflow/www/static/js/dag/details/taskInstance/Details.tsx
@@ -55,9 +55,11 @@ const Details = ({ gridInstance, taskInstance, group }:
Props) => {
const { data: tiHistory } = useTIHistory({
dagId,
taskId: taskId || "",
- runId: runId || "",
+ dagRunId: runId || "",
mapIndex: taskInstance?.mapIndex || -1,
- enabled: !!(finalTryNumber && finalTryNumber > 1) && !!taskId, // Only try
to look up task tries if try number > 1
+ options: {
+ enabled: !!(finalTryNumber && finalTryNumber > 1) && !!taskId, // Only
try to look up task tries if try number > 1
+ },
});
const [selectedTryNumber, setSelectedTryNumber] = useState(
@@ -69,7 +71,7 @@ const Details = ({ gridInstance, taskInstance, group }:
Props) => {
if (finalTryNumber) setSelectedTryNumber(finalTryNumber);
}, [finalTryNumber]);
- const tryInstance = tiHistory?.find(
+ const tryInstance = tiHistory?.taskInstances?.find(
(ti) => ti.tryNumber === selectedTryNumber
);
diff --git a/airflow/www/static/js/dag/details/taskInstance/Logs/index.test.tsx
b/airflow/www/static/js/dag/details/taskInstance/Logs/index.test.tsx
index e9c29ed4a8..74db45a7d2 100644
--- a/airflow/www/static/js/dag/details/taskInstance/Logs/index.test.tsx
+++ b/airflow/www/static/js/dag/details/taskInstance/Logs/index.test.tsx
@@ -27,7 +27,10 @@ import * as utils from "src/utils";
import * as useTaskLogModule from "src/api/useTaskLog";
import * as useTIHistory from "src/api/useTIHistory";
import * as useTaskInstance from "src/api/useTaskInstance";
-import type { TaskInstance } from "src/types/api-generated";
+import type {
+ TaskInstance,
+ TaskInstanceCollection,
+} from "src/types/api-generated";
import Logs from "./index";
@@ -64,22 +67,25 @@ describe("Test Logs Component.", () => {
} as UseQueryResult<TaskInstance, unknown>;
const tiHistoryValue = {
- data: [
- {
- tryNumber: 1,
- startDate: "2024-06-17T01:47:51.724946+00:00",
- endDate: "2024-06-17T01:50:51.724946+00:00",
- state: "failed",
- },
- {
- tryNumber: 2,
- startDate: "2024-06-18T01:47:51.724946+00:00",
- endDate: "2024-06-18T01:50:51.724946+00:00",
- state: "failed",
- },
- ],
+ data: {
+ taskInstances: [
+ {
+ tryNumber: 1,
+ startDate: "2024-06-17T01:47:51.724946+00:00",
+ endDate: "2024-06-17T01:50:51.724946+00:00",
+ state: "failed",
+ },
+ {
+ tryNumber: 2,
+ startDate: "2024-06-18T01:47:51.724946+00:00",
+ endDate: "2024-06-18T01:50:51.724946+00:00",
+ state: "failed",
+ },
+ ],
+ totalEntries: 2,
+ },
isSuccess: true,
- } as UseQueryResult<Partial<TaskInstance>[], unknown>;
+ } as UseQueryResult<TaskInstanceCollection>;
beforeEach(() => {
useTaskLogMock = jest
diff --git a/airflow/www/static/js/dag/details/taskInstance/TrySelector.tsx
b/airflow/www/static/js/dag/details/taskInstance/TrySelector.tsx
index 4377773f6b..5fc96803c8 100644
--- a/airflow/www/static/js/dag/details/taskInstance/TrySelector.tsx
+++ b/airflow/www/static/js/dag/details/taskInstance/TrySelector.tsx
@@ -49,9 +49,11 @@ const TrySelector = ({
const { data: tiHistory } = useTIHistory({
dagId: dagId || "",
taskId: taskId || "",
- runId: dagRunId || "",
+ dagRunId: dagRunId || "",
mapIndex,
- enabled: !!(finalTryNumber && finalTryNumber > 1) && !!taskId, // Only try
to look up task tries if try number > 1
+ options: {
+ enabled: !!(finalTryNumber && finalTryNumber > 1) && !!taskId, // Only
try to look up task tries if try number > 1
+ },
});
if (!finalTryNumber || finalTryNumber <= 1) return null;
@@ -59,7 +61,7 @@ const TrySelector = ({
const logAttemptDropdownLimit = 10;
const showDropdown = finalTryNumber > logAttemptDropdownLimit;
- const tries = (tiHistory || []).filter(
+ const tries = (tiHistory?.taskInstances || []).filter(
(t) => t?.startDate !== taskInstance?.startDate
);
tries?.push(taskInstance);
diff --git a/airflow/www/templates/airflow/dag.html
b/airflow/www/templates/airflow/dag.html
index f4174e55f0..d3a7995440 100644
--- a/airflow/www/templates/airflow/dag.html
+++ b/airflow/www/templates/airflow/dag.html
@@ -60,7 +60,7 @@
<meta name="calendar_data_url" content="{{ url_for('Airflow.calendar_data')
}}">
<meta name="next_run_datasets_url" content="{{
url_for('Airflow.next_run_datasets', dag_id=dag.dag_id) }}">
<meta name="grid_url" content="{{ url_for('Airflow.grid', dag_id=dag.dag_id)
}}">
- <meta name="ti_history_url" content="{{ url_for('Airflow.ti_history') }}">
+ <meta name="task_tries_api" content="{{
url_for('/api/v1.airflow_api_connexion_endpoints_task_instance_endpoint_get_task_instance_tries',
dag_id='_DAG_ID_', dag_run_id='_DAG_RUN_ID_', task_id='_TASK_ID_') }}">
<meta name="datasets_url" content="{{ url_for('Airflow.datasets') }}">
<meta name="grid_url_no_root" content="{{ url_for('Airflow.grid',
dag_id=dag.dag_id, num_runs=num_runs_arg, base_date=base_date_arg) }}">
<meta name="graph_url" content="{{ url_for('Airflow.graph',
dag_id=dag.dag_id, root=root) }}">
diff --git a/airflow/www/views.py b/airflow/www/views.py
index f98702ff6e..cb19dbc494 100644
--- a/airflow/www/views.py
+++ b/airflow/www/views.py
@@ -110,7 +110,6 @@ from airflow.models.dataset import
DagScheduleDatasetReference, DatasetDagRunQue
from airflow.models.errors import ParseImportError
from airflow.models.serialized_dag import SerializedDagModel
from airflow.models.taskinstance import TaskInstance, TaskInstanceNote
-from airflow.models.taskinstancehistory import TaskInstanceHistory as TIHistory
from airflow.plugins_manager import PLUGINS_ATTRIBUTES_TO_DUMP
from airflow.providers_manager import ProvidersManager
from airflow.security import permissions
@@ -3636,40 +3635,6 @@ class Airflow(AirflowBaseView):
{"Content-Type": "application/json; charset=utf-8"},
)
- @expose("/object/task_instance_history")
- @provide_session
- @auth.has_access_dag("GET", DagAccessEntity.TASK_INSTANCE)
- def ti_history(self, session: Session = NEW_SESSION):
- dag_id = request.args.get("dag_id")
- task_id = request.args.get("task_id")
- run_id = request.args.get("run_id")
- map_index = request.args.get("map_index", -1, type=int)
-
- ti_history = (
- session.query(TIHistory)
- .filter(
- TIHistory.dag_id == dag_id,
- TIHistory.task_id == task_id,
- TIHistory.run_id == run_id,
- TIHistory.map_index == map_index,
- )
- .order_by(TIHistory.try_number.asc())
- .all()
- )
-
- attrs = TaskInstance.__table__.columns.keys()
-
- data = [{attr: getattr(ti, attr) for attr in attrs} for ti in
ti_history]
-
- for entity in data:
- entity["dag_run_id"] = entity.pop("run_id")
- entity["queued_when"] = entity.pop("queued_dttm")
-
- return (
- htmlsafe_json_dumps(data, separators=(",", ":"),
cls=utils_json.WebEncoder),
- {"Content-Type": "application/json; charset=utf-8"},
- )
-
@expose("/robots.txt")
@action_logging
def robots(self):
diff --git a/tests/www/views/test_views_ti_history.py
b/tests/www/views/test_views_ti_history.py
deleted file mode 100644
index cc7a933e94..0000000000
--- a/tests/www/views/test_views_ti_history.py
+++ /dev/null
@@ -1,44 +0,0 @@
-# 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.
-from __future__ import annotations
-
-import pytest
-
-from airflow.models.taskinstancehistory import TaskInstanceHistory
-from tests.test_utils.db import clear_db_runs
-
-pytestmark = pytest.mark.db_test
-
-
-class TestTIHistoryEndpoint:
- @pytest.fixture(autouse=True)
- def cleanup(self):
- clear_db_runs()
- yield
- clear_db_runs()
-
-
-class TestGetTIHistory(TestTIHistoryEndpoint):
- def test_should_respond_200(self, admin_client, create_task_instance,
session):
- ti = create_task_instance(dag_id="test_dag", task_id="test_task",
run_id="test_run_id")
- TaskInstanceHistory.record_ti(ti)
- assert session.query(TaskInstanceHistory).count() == 1
- response = admin_client.get(
-
"/object/task_instance_history?dag_id=test_dag&task_id=test_task&run_id=test_run_id"
- )
- assert response.status_code == 200
- assert len(response.json) == 1