blob: 860e5ba54f32bb3d7d351978e5ff56a9988f7c05 [file] [log] [blame]
/*
* 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 { IconNames } from '@blueprintjs/icons';
import React from 'react';
import { PluralPairIfNeeded } from '../../../components/plural-pair-if-needed/plural-pair-if-needed';
import { useQueryManager } from '../../../hooks';
import { Api } from '../../../singletons';
import { lookupBy, pluralIfNeeded, queryDruidSql } from '../../../utils';
import { Capabilities } from '../../../utils';
import { HomeViewCard } from '../home-view-card/home-view-card';
function getTaskStatus(d: any) {
return d.statusCode === 'RUNNING' ? d.runnerStatusCode : d.statusCode;
}
export interface TaskCounts {
SUCCESS?: number;
FAILED?: number;
RUNNING?: number;
PENDING?: number;
WAITING?: number;
}
export interface TasksCardProps {
capabilities: Capabilities;
}
export const TasksCard = React.memo(function TasksCard(props: TasksCardProps) {
const [taskCountState] = useQueryManager<Capabilities, TaskCounts>({
processQuery: async capabilities => {
if (capabilities.hasSql()) {
const taskCountsFromQuery: { status: string; count: number }[] = await queryDruidSql({
query: `SELECT
CASE WHEN "status" = 'RUNNING' THEN "runner_status" ELSE "status" END AS "status",
COUNT (*) AS "count"
FROM sys.tasks
GROUP BY 1`,
});
return lookupBy(
taskCountsFromQuery,
x => x.status,
x => x.count,
);
} else if (capabilities.hasOverlordAccess()) {
const tasks: any[] = (await Api.instance.get('/druid/indexer/v1/tasks')).data;
return {
SUCCESS: tasks.filter(d => getTaskStatus(d) === 'SUCCESS').length,
FAILED: tasks.filter(d => getTaskStatus(d) === 'FAILED').length,
RUNNING: tasks.filter(d => getTaskStatus(d) === 'RUNNING').length,
PENDING: tasks.filter(d => getTaskStatus(d) === 'PENDING').length,
WAITING: tasks.filter(d => getTaskStatus(d) === 'WAITING').length,
};
} else {
throw new Error(`must have SQL or overlord access`);
}
},
initQuery: props.capabilities,
});
const taskCounts = taskCountState.data;
const successTaskCount = taskCounts ? taskCounts.SUCCESS : 0;
const failedTaskCount = taskCounts ? taskCounts.FAILED : 0;
const runningTaskCount = taskCounts ? taskCounts.RUNNING : 0;
const pendingTaskCount = taskCounts ? taskCounts.PENDING : 0;
const waitingTaskCount = taskCounts ? taskCounts.WAITING : 0;
return (
<HomeViewCard
className="tasks-card"
href={'#ingestion'}
icon={IconNames.GANTT_CHART}
title={'Tasks'}
loading={taskCountState.loading}
error={taskCountState.error}
>
<PluralPairIfNeeded
firstCount={runningTaskCount}
firstSingular="running task"
secondCount={pendingTaskCount}
secondSingular="pending task"
/>
{Boolean(successTaskCount) && (
<p>{pluralIfNeeded(successTaskCount || 0, 'successful task')}</p>
)}
{Boolean(waitingTaskCount) && <p>{pluralIfNeeded(waitingTaskCount || 0, 'waiting task')}</p>}
{Boolean(failedTaskCount) && <p>{pluralIfNeeded(failedTaskCount || 0, 'failed task')}</p>}
{!(
Boolean(runningTaskCount) ||
Boolean(pendingTaskCount) ||
Boolean(successTaskCount) ||
Boolean(waitingTaskCount) ||
Boolean(failedTaskCount)
) && <p>There are no tasks</p>}
</HomeViewCard>
);
});