From a3d9b0e7cf7ed9a4514ee4fd31227f156f4a7418 Mon Sep 17 00:00:00 2001 From: Xin Hao Zhang Date: Mon, 19 Sep 2022 14:05:26 -0400 Subject: [PATCH] ui/cluster-ui: fix jobs page polling Fixes #68109 Previously, the jobs page would not poll for new data until a re-render was triggered. This commit updates the jobs page polling to every 10s regardless of whether or not the rest of the page has changed. Release note (bug fix): jobs page refreshes page data at an interval of 10s --- .../cluster-ui/src/jobs/jobsPage/jobsPage.tsx | 29 +++++++++---------- .../cluster-ui/src/store/jobs/jobs.sagas.ts | 21 ++------------ .../db-console/src/redux/apiReducers.ts | 4 +-- .../db-console/src/views/jobs/jobsPage.tsx | 4 ++- 4 files changed, 22 insertions(+), 36 deletions(-) diff --git a/pkg/ui/workspaces/cluster-ui/src/jobs/jobsPage/jobsPage.tsx b/pkg/ui/workspaces/cluster-ui/src/jobs/jobsPage/jobsPage.tsx index c373d4d1de0c..5c6a198ba2fb 100644 --- a/pkg/ui/workspaces/cluster-ui/src/jobs/jobsPage/jobsPage.tsx +++ b/pkg/ui/workspaces/cluster-ui/src/jobs/jobsPage/jobsPage.tsx @@ -56,6 +56,8 @@ export type JobsPageProps = JobsPageStateProps & RouteComponentProps; export class JobsPage extends React.Component { + refreshDataInterval: NodeJS.Timeout; + constructor(props: JobsPageProps) { super(props); @@ -94,29 +96,26 @@ export class JobsPage extends React.Component { } } - private refresh(props = this.props): void { + refresh(): void { const jobsRequest = new cockroach.server.serverpb.JobsRequest({ - status: props.status, - type: props.type, - limit: parseInt(props.show, 10), + status: this.props.status, + type: this.props.type, + limit: parseInt(this.props.show, 10), }); - props.onFilterChange - ? props.onFilterChange(jobsRequest) - : props.refreshJobs(jobsRequest); + this.props.onFilterChange + ? this.props.onFilterChange(jobsRequest) + : this.props.refreshJobs(jobsRequest); } componentDidMount(): void { + // Refresh every 10 seconds this.refresh(); + this.refreshDataInterval = setInterval(() => this.refresh(), 10 * 1000); } - componentDidUpdate(prevProps: JobsPageProps): void { - if ( - prevProps.status !== this.props.status || - prevProps.type !== this.props.type || - prevProps.show !== this.props.show - ) { - this.refresh(); - } + componentWillUnmount(): void { + if (!this.refreshDataInterval) return; + clearInterval(this.refreshDataInterval); } onStatusSelected = (item: string): void => { diff --git a/pkg/ui/workspaces/cluster-ui/src/store/jobs/jobs.sagas.ts b/pkg/ui/workspaces/cluster-ui/src/store/jobs/jobs.sagas.ts index e54d6997805a..7b661639caf3 100644 --- a/pkg/ui/workspaces/cluster-ui/src/store/jobs/jobs.sagas.ts +++ b/pkg/ui/workspaces/cluster-ui/src/store/jobs/jobs.sagas.ts @@ -8,14 +8,12 @@ // by the Apache License, Version 2.0, included in the file // licenses/APL.txt. -import { all, call, delay, put, takeLatest } from "redux-saga/effects"; +import { all, call, put, takeLatest } from "redux-saga/effects"; import { cockroach } from "@cockroachlabs/crdb-protobuf-client"; import { actions } from "./jobs.reducer"; import { getJobs, JobsRequest } from "src/api/jobsApi"; -import { CACHE_INVALIDATION_PERIOD, throttleWithReset } from "../utils"; import { PayloadAction } from "@reduxjs/toolkit"; -import { rootActions } from "../reducers"; export function* refreshJobsSaga(action: PayloadAction) { yield put(actions.request(action.payload)); @@ -30,29 +28,16 @@ export function* requestJobsSaga(action: PayloadAction): any { } } -export function* receivedJobsSaga(delayMs: number) { - yield delay(delayMs); - yield put(actions.invalidated()); -} - export function* updateFilteredJobsSaga(action: PayloadAction) { yield put(actions.invalidated()); const req = new cockroach.server.serverpb.JobsRequest(action.payload); yield put(actions.refresh(req)); } -export function* jobsSaga( - cacheInvalidationPeriod: number = CACHE_INVALIDATION_PERIOD, -) { +export function* jobsSaga() { yield all([ - throttleWithReset( - cacheInvalidationPeriod, - actions.refresh, - [actions.invalidated, rootActions.resetState], - refreshJobsSaga, - ), + takeLatest(actions.refresh, refreshJobsSaga), takeLatest(actions.request, requestJobsSaga), - takeLatest(actions.received, receivedJobsSaga, cacheInvalidationPeriod), takeLatest(actions.updateFilteredJobs, updateFilteredJobsSaga), ]); } diff --git a/pkg/ui/workspaces/db-console/src/redux/apiReducers.ts b/pkg/ui/workspaces/db-console/src/redux/apiReducers.ts index 0d07274a7011..67ac931bfa60 100644 --- a/pkg/ui/workspaces/db-console/src/redux/apiReducers.ts +++ b/pkg/ui/workspaces/db-console/src/redux/apiReducers.ts @@ -194,7 +194,7 @@ const jobsReducerObj = new KeyedCachedDataReducer( api.getJobs, "jobs", jobsRequestKey, - moment.duration(10, "s"), + null, moment.duration(1, "minute"), ); export const refreshJobs = jobsReducerObj.refresh; @@ -206,7 +206,7 @@ const jobReducerObj = new KeyedCachedDataReducer( api.getJob, "job", jobRequestKey, - moment.duration(10, "s"), + null, ); export const refreshJob = jobReducerObj.refresh; diff --git a/pkg/ui/workspaces/db-console/src/views/jobs/jobsPage.tsx b/pkg/ui/workspaces/db-console/src/views/jobs/jobsPage.tsx index 9d10ffcd54ad..b2c76a0a2573 100644 --- a/pkg/ui/workspaces/db-console/src/views/jobs/jobsPage.tsx +++ b/pkg/ui/workspaces/db-console/src/views/jobs/jobsPage.tsx @@ -77,7 +77,9 @@ const mapStateToProps = ( const key = jobsKey(status, type, parseInt(show, 10)); const jobsState = selectJobsState(state, key); const jobs = jobsState ? jobsState.data : null; - const jobsLoading = jobsState ? jobsState.inFlight : false; + const jobsLoading = jobsState + ? jobsState.inFlight && !jobsState.valid + : false; const jobsError = jobsState ? jobsState.lastError : null; return { sort,