This is an automated email from the ASF dual-hosted git repository.
agrove pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/arrow-ballista.git
The following commit(s) were added to refs/heads/master by this push:
new 42e9617d Show job stages metrics (#323)
42e9617d is described below
commit 42e9617de690695965387eb0f1bf36ab061effb1
Author: Stefan Stanciulescu
<[email protected]>
AuthorDate: Fri Oct 7 05:27:31 2022 -0700
Show job stages metrics (#323)
* Add support for viewing stage metrics for a job by clicking on the job id
* Cleanup
* Formatting and cleanup
---
.../scheduler/src/components/JobStagesMetrics.tsx | 92 ++++++++++++++++++++++
.../ui/scheduler/src/components/QueriesList.tsx | 64 +++++++++++++--
2 files changed, 150 insertions(+), 6 deletions(-)
diff --git a/ballista/ui/scheduler/src/components/JobStagesMetrics.tsx
b/ballista/ui/scheduler/src/components/JobStagesMetrics.tsx
new file mode 100644
index 00000000..84dc7e14
--- /dev/null
+++ b/ballista/ui/scheduler/src/components/JobStagesMetrics.tsx
@@ -0,0 +1,92 @@
+// 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.
+
+import { Skeleton, Box } from "@chakra-ui/react";
+import { Column, DataTable } from "./DataTable";
+
+export enum StageStatus {
+ QUEUED = "QUEUED",
+ RUNNING = "RUNNING",
+ FAILED = "FAILED",
+ COMPLETED = "COMPLETED",
+}
+
+export interface Stage {
+ stage_id: string;
+ stage_status: StageStatus;
+ input_rows: number;
+ output_rows: number;
+ elapsed_compute: string;
+}
+
+export interface StagesListProps {
+ stages?: Stage[];
+}
+
+const columns: Column<any>[] = [
+ {
+ Header: "Stage ID",
+ accessor: "stage_id",
+ },
+ {
+ Header: "Status",
+ accessor: "stage_status",
+ },
+ {
+ Header: "Input Rows",
+ accessor: "input_rows",
+ },
+ {
+ Header: "Output Rows",
+ accessor: "output_rows",
+ },
+ {
+ Header: "Computation time",
+ accessor: "elapsed_compute",
+ },
+];
+
+const getSkeleton = () => (
+ <>
+ <Skeleton height={5} />
+ <Skeleton height={5} />
+ <Skeleton height={5} />
+ <Skeleton height={5} />
+ <Skeleton height={5} />
+ </>
+);
+
+export const JobStagesQueries: React.FunctionComponent<StagesListProps> = ({
+ stages,
+}) => {
+ const isLoaded = typeof stages !== "undefined";
+
+ return (
+ <Box w={"100%"} flex={1}>
+ {isLoaded ? (
+ <DataTable
+ columns={columns}
+ data={stages || []}
+ pageSize={10}
+ pb={10}
+ />
+ ) : (
+ getSkeleton()
+ )}
+ </Box>
+ );
+};
diff --git a/ballista/ui/scheduler/src/components/QueriesList.tsx
b/ballista/ui/scheduler/src/components/QueriesList.tsx
index 38526147..0fb18b29 100644
--- a/ballista/ui/scheduler/src/components/QueriesList.tsx
+++ b/ballista/ui/scheduler/src/components/QueriesList.tsx
@@ -16,13 +16,11 @@
// under the License.
import React, { useEffect, useState } from "react";
+import { ExternalLinkIcon } from "@chakra-ui/icons";
import {
CircularProgress,
CircularProgressLabel,
- VStack,
Skeleton,
- Stack,
- Text,
Flex,
Box,
useDisclosure,
@@ -34,12 +32,14 @@ import {
ModalFooter,
ModalHeader,
ModalOverlay,
+ Link,
} from "@chakra-ui/react";
-import { Column, DataTable, LinkCell } from "./DataTable";
+import { Column, DataTable } from "./DataTable";
import { FaStop } from "react-icons/fa";
import { GrDocumentDownload, GrOverview } from "react-icons/gr";
import fileDownload from "js-file-download";
import SVG from "react-inlinesvg";
+import { JobStagesQueries } from "./JobStagesMetrics";
export enum QueryStatus {
QUEUED = "QUEUED",
@@ -113,7 +113,9 @@ export const ActionsCell: (props: any) => React.ReactNode =
(props: any) => {
<Modal isOpen={isOpen} size="small" onClose={onClose}>
<ModalOverlay />
<ModalContent>
- <ModalHeader>Graph for {props.value} job</ModalHeader>
+ <ModalHeader textAlign={"center"}>
+ Graph for {props.value} job
+ </ModalHeader>
<ModalCloseButton />
<ModalBody margin="auto">
<SVG innerRef={ref} src={dot_data} width="auto" />
@@ -129,6 +131,56 @@ export const ActionsCell: (props: any) => React.ReactNode
= (props: any) => {
);
};
+export const JobLinkCell: (props: any) => React.ReactNode = (props: any) => {
+ const [stages, setData] = useState();
+ const [loaded, setLoaded] = useState(false);
+ const { isOpen, onOpen, onClose } = useDisclosure();
+
+ const getStages = (url: string) => {
+ fetch(url, {
+ method: "GET",
+ headers: {
+ Accept: "application/json",
+ },
+ }).then(async (res) => {
+ const jsonObj = await res.json();
+ setData(jsonObj["stages"]);
+ });
+ };
+
+ useEffect(() => {
+ if (isOpen && !loaded) {
+ getStages("/api/job/" + props.value + "/stages");
+ setLoaded(true);
+ }
+ }, [stages, isOpen]);
+
+ return (
+ <Flex>
+ <Link onClick={onOpen} icon>
+ {props.value} <ExternalLinkIcon mx="2px" />
+ </Link>
+ <Modal isOpen={isOpen} size="small" onClose={onClose}>
+ <ModalOverlay />
+ <ModalContent>
+ <ModalHeader textAlign={"center"}>
+ Stages metrics for {props.value} job
+ </ModalHeader>
+ <ModalCloseButton />
+ <ModalBody margin="auto">
+ <JobStagesQueries stages={stages} />
+ </ModalBody>
+ <ModalFooter>
+ <Button colorScheme="blue" mr={3} onClick={onClose}>
+ Close
+ </Button>
+ </ModalFooter>
+ </ModalContent>
+ </Modal>
+ </Flex>
+ );
+};
+
export const ProgressCell: (props: any) => React.ReactNode = (props: any) => {
return (
<CircularProgress value={props.value} color="orange.400">
@@ -141,7 +193,7 @@ const columns: Column<any>[] = [
{
Header: "Job ID",
accessor: "job_id",
- Cell: LinkCell,
+ Cell: JobLinkCell,
},
{
Header: "Job Name",