diff --git a/public/models/interfaces.ts b/public/models/interfaces.ts
index f85a5912..f026b79c 100644
--- a/public/models/interfaces.ts
+++ b/public/models/interfaces.ts
@@ -85,6 +85,7 @@ export type UiMetaData = {
[key: string]: UiFeature;
};
};
+
export type Detector = {
primaryTerm: number;
seqNo: number;
@@ -103,7 +104,7 @@ export type Detector = {
enabledTime?: number;
disabledTime?: number;
curState: DETECTOR_STATE;
- initializationError: string;
+ stateError: string;
};
export type DetectorListItem = {
diff --git a/public/pages/DetectorResults/components/DetectorState/DetectorInitializationFailure.tsx b/public/pages/DetectorResults/components/DetectorState/DetectorInitializationFailure.tsx
deleted file mode 100644
index f1733634..00000000
--- a/public/pages/DetectorResults/components/DetectorState/DetectorInitializationFailure.tsx
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License").
- * You may not use this file except in compliance with the License.
- * A copy of the License is located at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * or in the "license" file accompanying this file. This file 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 React from 'react';
-import { EuiButton, EuiEmptyPrompt, EuiIcon } from '@elastic/eui';
-import { Fragment } from 'react';
-import { Detector } from '../../../../models/interfaces';
-
-export interface DetectorInitializationFailureProps {
- detector: Detector;
- onStartDetector(): void;
- failureDetail: any;
- onSwitchToConfiguration(): void;
-}
-
-export const DetectorInitializationFailure = (
- props: DetectorInitializationFailureProps
-) => {
- return (
-
-
-
-
- {`The detector is not initialized because ${props.failureDetail.cause}`}
-
-
- }
- body={
-
- {`${props.failureDetail.actionItem}`}
-
- }
- actions={[
-
- View detector configuration
- ,
-
- Restart detector
- ,
- ]}
- />
- );
-};
diff --git a/public/pages/DetectorResults/components/DetectorState/DetectorInitializing.tsx b/public/pages/DetectorResults/components/DetectorState/DetectorInitializing.tsx
deleted file mode 100644
index 2a11d9a3..00000000
--- a/public/pages/DetectorResults/components/DetectorState/DetectorInitializing.tsx
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License").
- * You may not use this file except in compliance with the License.
- * A copy of the License is located at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * or in the "license" file accompanying this file. This file 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 React from 'react';
-import { EuiButton, EuiEmptyPrompt, EuiLoadingSpinner } from '@elastic/eui';
-import { Fragment } from 'react';
-import { Detector } from '../../../../models/interfaces';
-import {
- getDetectorInitializationInfo,
- IS_INIT_OVERTIME_FIELD,
- INIT_DETAILS_FIELD,
- INIT_ERROR_MESSAGE_FIELD,
- INIT_ACTION_ITEM_FIELD,
-} from '../../utils/utils';
-import { get } from 'lodash';
-
-export interface DetectorInitializingProps {
- detector: Detector;
- onSwitchToConfiguration(): void;
-}
-
-export const DetectorInitializing = (props: DetectorInitializingProps) => {
- const initializationInfo = getDetectorInitializationInfo(props.detector);
- const isInitOvertime = get(initializationInfo, IS_INIT_OVERTIME_FIELD, false);
- const initDetails = get(initializationInfo, INIT_DETAILS_FIELD, {});
- const initErrorMessage = get(initDetails, INIT_ERROR_MESSAGE_FIELD, '');
- const initActionItem = get(initDetails, INIT_ACTION_ITEM_FIELD, '');
-
- return (
-
-
- The detector is initializing...
-
- }
- body={
-
- {!isInitOvertime
- ? [
-
- Based on your latest update to the detector configuration, the
- detector is collecting data to generate accurate real-time
- anomalies.
-
,
-
- The longer the detector interval is, the more time this will
- take.
-
,
- ]
- : [
-
- {`Detector initialization is not complete because ${initErrorMessage}.`}
-
,
- {`${initActionItem}`}
,
- ]}
-
- }
- actions={
-
- View detector configuration
-
- }
- />
- );
-};
diff --git a/public/pages/DetectorResults/containers/AnomalyResults.tsx b/public/pages/DetectorResults/containers/AnomalyResults.tsx
index cd971485..efb9d8d2 100644
--- a/public/pages/DetectorResults/containers/AnomalyResults.tsx
+++ b/public/pages/DetectorResults/containers/AnomalyResults.tsx
@@ -24,7 +24,7 @@ import {
} from '@elastic/eui';
import { get } from 'lodash';
import React, { useEffect, Fragment } from 'react';
-import { useSelector } from 'react-redux';
+import { useSelector, useDispatch } from 'react-redux';
import { RouteComponentProps } from 'react-router';
//@ts-ignore
import chrome from 'ui/chrome';
@@ -40,6 +40,9 @@ import {
INIT_ERROR_MESSAGE_FIELD,
INIT_ACTION_ITEM_FIELD,
} from '../utils/utils';
+import { getDetector } from '../../../redux/reducers/ad';
+import { MIN_IN_MILLI_SECS } from '../../../../server/utils/constants';
+import { getInitFailureMessageAndActionItem } from '../../DetectorDetail/utils/helpers';
interface AnomalyResultsProps extends RouteComponentProps {
detectorId: string;
@@ -48,6 +51,7 @@ interface AnomalyResultsProps extends RouteComponentProps {
}
export function AnomalyResults(props: AnomalyResultsProps) {
+ const dispatch = useDispatch();
const detectorId = props.detectorId;
const detector = useSelector(
(state: AppState) => state.ad.detectors[detectorId]
@@ -61,6 +65,19 @@ export function AnomalyResults(props: AnomalyResultsProps) {
]);
}, []);
+ const fetchDetector = async () => {
+ await dispatch(getDetector(detectorId));
+ };
+
+ useEffect(() => {
+ if (detector && detector.curState === DETECTOR_STATE.INIT) {
+ const id = setInterval(fetchDetector, MIN_IN_MILLI_SECS);
+ return () => {
+ clearInterval(id);
+ };
+ }
+ }, [detector]);
+
const monitors = useSelector((state: AppState) => state.alerting.monitors);
const monitor = get(monitors, `${detectorId}.0`);
@@ -78,18 +95,23 @@ export function AnomalyResults(props: AnomalyResultsProps) {
// @ts-ignore
isDetectorPaused && detector.lastUpdateTime > detector.disabledTime;
- const isDetectorInitializingAgain =
- detector &&
- detector.curState === DETECTOR_STATE.INIT &&
- detector.enabled &&
- detector.disabledTime;
+ const isDetectorInitializing =
+ detector && detector.curState === DETECTOR_STATE.INIT;
const initializationInfo = getDetectorInitializationInfo(detector);
+
const isInitOvertime = get(initializationInfo, IS_INIT_OVERTIME_FIELD, false);
const initDetails = get(initializationInfo, INIT_DETAILS_FIELD, {});
const initErrorMessage = get(initDetails, INIT_ERROR_MESSAGE_FIELD, '');
const initActionItem = get(initDetails, INIT_ACTION_ITEM_FIELD, '');
+ const isInitializingNormally = isDetectorInitializing && !isInitOvertime;
+
+ const isDetectorFailed =
+ detector &&
+ (detector.curState === DETECTOR_STATE.INIT_FAILURE ||
+ detector.curState === DETECTOR_STATE.UNEXPECTED_FAILURE);
+
return (
@@ -99,19 +121,39 @@ export function AnomalyResults(props: AnomalyResultsProps) {
{isDetectorRunning ||
isDetectorPaused ||
- isDetectorInitializingAgain ? (
+ isDetectorInitializing ||
+ isDetectorFailed ? (
- {isDetectorUpdated || isDetectorInitializingAgain ? (
+ {isDetectorUpdated ||
+ isDetectorInitializing ||
+ isDetectorFailed ? (
{isDetectorUpdated ? (
@@ -119,25 +161,42 @@ export function AnomalyResults(props: AnomalyResultsProps) {
Restart the detector to see accurate anomalies based
on configuration changes.
- ) : !isInitOvertime ? (
+ ) : isInitializingNormally ? (
After the initialization is complete, you will see the
anomaly results based on your latest configuration
changes.
- ) : (
+ ) : isInitOvertime ? (
{`${initActionItem}`}
+ ) : (
+ // detector has failure
+ {`${get(
+ getInitFailureMessageAndActionItem(
+ //@ts-ignore
+ detector.stateError
+ ),
+ 'actionItem',
+ ''
+ )}`}
)}
View detector configuration
- {isDetectorUpdated ? (
+ {isDetectorUpdated || isDetectorFailed ? (
- ) : detector && detector.curState !== DETECTOR_STATE.RUNNING ? (
+ ) : detector ? (
) : (
- {`Not available when the detector is ${props.detector.curState.toLowerCase()}.`}
+
+ {'Not available when the detector ' +
+ `${
+ props.detector.curState === DETECTOR_STATE.INIT_FAILURE ||
+ props.detector.curState === DETECTOR_STATE.UNEXPECTED_FAILURE
+ ? 'initialization has failed.'
+ : `is ${props.detector.curState.toLowerCase()}.`
+ }`}
+
)}
diff --git a/public/pages/DetectorResults/containers/DetectorStateDetails.tsx b/public/pages/DetectorResults/containers/DetectorStateDetails.tsx
index d9526c61..8ac127a2 100644
--- a/public/pages/DetectorResults/containers/DetectorStateDetails.tsx
+++ b/public/pages/DetectorResults/containers/DetectorStateDetails.tsx
@@ -13,11 +13,8 @@
* permissions and limitations under the License.
*/
import React, { useEffect } from 'react';
-import { getInitFailureMessageAndActionItem } from '../../DetectorDetail/utils/helpers';
import { DETECTOR_STATE } from '../../../utils/constants';
import { DetectorStopped } from '../components/DetectorState/DetectorStopped';
-import { DetectorInitializing } from '../components/DetectorState/DetectorInitializing';
-import { DetectorInitializationFailure } from '../components/DetectorState/DetectorInitializationFailure';
import { DetectorFeatureRequired } from '../components/DetectorState/DetectorFeatureRequired';
import { DetectorUnknownState } from '../components/DetectorState/DetectorUnknownState';
import { useDispatch, useSelector } from 'react-redux';
@@ -49,26 +46,6 @@ export const DetectorStateDetails = (props: DetectorStateDetailsProp) => {
onSwitchToConfiguration={props.onSwitchToConfiguration}
/>
);
- case DETECTOR_STATE.INIT:
- return (
-
- );
- case DETECTOR_STATE.UNEXPECTED_FAILURE:
- case DETECTOR_STATE.INIT_FAILURE:
- const failureDetail = getInitFailureMessageAndActionItem(
- detector.initializationError
- );
- return (
-
- );
case DETECTOR_STATE.FEATURE_REQUIRED:
return (
{
return (
detector &&
detector.curState === DETECTOR_STATE.INIT &&
- detector.initializationError &&
- !detector.initializationError.includes(NO_RCF_MODEL_ERROR_MESSAGE) &&
+ detector.stateError &&
+ !detector.stateError.includes(NO_RCF_MODEL_ERROR_MESSAGE) &&
//@ts-ignore
currentTime
.subtract(
@@ -63,16 +63,14 @@ const getInitOverTimeDetails = (detector: Detector) => {
[INIT_ERROR_MESSAGE_FIELD]: '',
[INIT_ACTION_ITEM_FIELD]: '',
};
- if (!detector.initializationError) {
+ if (!detector.stateError) {
return result;
}
- if (detector.initializationError.includes(NO_FULL_SHINGLE_ERROR_MESSAGE)) {
+ if (detector.stateError.includes(NO_FULL_SHINGLE_ERROR_MESSAGE)) {
result[INIT_ERROR_MESSAGE_FIELD] = 'of insufficient data';
result[INIT_ACTION_ITEM_FIELD] =
DETECTOR_INIT_FAILURES.NO_TRAINING_DATA.actionItem;
- } else if (
- detector.initializationError.includes(NO_DATA_IN_WINDOW_ERROR_MESSAGE)
- ) {
+ } else if (detector.stateError.includes(NO_DATA_IN_WINDOW_ERROR_MESSAGE)) {
result[INIT_ERROR_MESSAGE_FIELD] = 'no data could be found';
result[INIT_ACTION_ITEM_FIELD] =
'Make sure your source index has sufficient data in the current detector interval and try again.';
diff --git a/public/pages/createDetector/hooks/useFetchDetectorInfo.ts b/public/pages/createDetector/hooks/useFetchDetectorInfo.ts
index edc78735..f30e3bd3 100644
--- a/public/pages/createDetector/hooks/useFetchDetectorInfo.ts
+++ b/public/pages/createDetector/hooks/useFetchDetectorInfo.ts
@@ -26,11 +26,10 @@ import { getMappings } from '../../../redux/reducers/elasticsearch';
// 2. Gets index mapping
export const useFetchDetectorInfo = (
detectorId: string
-):
-{
+): {
detector: Detector;
hasError: boolean;
- isLoadingDetector: boolean;
+ isLoadingDetector: boolean;
} => {
const dispatch = useDispatch();
const detector = useSelector(
diff --git a/public/redux/reducers/__tests__/utils.ts b/public/redux/reducers/__tests__/utils.ts
index c372753c..d936df71 100644
--- a/public/redux/reducers/__tests__/utils.ts
+++ b/public/redux/reducers/__tests__/utils.ts
@@ -105,7 +105,7 @@ export const getRandomDetector = (isCreate: boolean = true): Detector => {
.subtract(1, 'days')
.valueOf(),
curState: DETECTOR_STATE.INIT,
- initializationError: '',
+ stateError: '',
};
};
diff --git a/public/redux/reducers/ad.ts b/public/redux/reducers/ad.ts
index 8bf8fe7a..c6d79839 100644
--- a/public/redux/reducers/ad.ts
+++ b/public/redux/reducers/ad.ts
@@ -112,7 +112,7 @@ const reducer = handleActions(
enabled: true,
enabledTime: moment().valueOf(),
curState: DETECTOR_STATE.INIT,
- initializationError: '',
+ stateError: '',
},
},
}),
@@ -138,7 +138,7 @@ const reducer = handleActions(
enabled: false,
disabledTime: moment().valueOf(),
curState: DETECTOR_STATE.DISABLED,
- initializationError: '',
+ stateError: '',
},
},
}),
diff --git a/server/routes/ad.ts b/server/routes/ad.ts
index dd562b23..7d27affe 100644
--- a/server/routes/ad.ts
+++ b/server/routes/ad.ts
@@ -199,7 +199,7 @@ const getDetector = async (
...(detectorState !== undefined ? { curState: detectorState.state } : {}),
...(detectorState !== undefined
? //@ts-ignore
- { initializationError: detectorState.error }
+ { stateError: detectorState.error }
: {}),
};
return {