Skip to content

Commit

Permalink
Refactor useEnableDataFeed to split disablement and enablement logic
Browse files Browse the repository at this point in the history
  • Loading branch information
machadoum committed Apr 25, 2023
1 parent 34ebddc commit 9981451
Show file tree
Hide file tree
Showing 8 changed files with 288 additions and 269 deletions.

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -20,17 +20,20 @@ import { setupMlJob, startDatafeeds, stopDatafeeds } from '../api';
import type { ErrorResponse, SecurityJob } from '../types';
import * as i18n from './translations';

// Enable/Disable Job & Datafeed -- passed to JobsTable for use as callback on JobSwitch
// Enable/Disable Job & Datafeed
export const useEnableDataFeed = () => {
const { telemetry } = useKibana().services;

const { addError } = useAppToasts();
const [isLoading, setIsLoading] = useState(false);

const enableDatafeed = useCallback(
async (job: SecurityJob, latestTimestampMs: number, enable: boolean) => {
submitTelemetry(job, enable);
async (job: SecurityJob, latestTimestampMs: number) => {
setIsLoading(true);
track(
METRIC_TYPE.COUNT,
job.isElasticJob ? TELEMETRY_EVENT.SIEM_JOB_ENABLED : TELEMETRY_EVENT.CUSTOM_JOB_ENABLED
);

if (!job.isInstalled) {
try {
Expand All @@ -40,16 +43,15 @@ export const useEnableDataFeed = () => {
jobIdErrorFilter: [job.id],
groups: job.groups,
});
setIsLoading(false);
telemetry.reportMLJobUpdate({
jobId: job.id,
isElasticJob: job.isElasticJob,
moduleId: job.moduleId,
status: ML_JOB_TELEMETRY_STATUS.moduleInstalled,
});
} catch (error) {
addError(error, { title: i18n.CREATE_JOB_FAILURE });
setIsLoading(false);
addError(error, { title: i18n.CREATE_JOB_FAILURE });
telemetry.reportMLJobUpdate({
jobId: job.id,
isElasticJob: job.isElasticJob,
Expand All @@ -67,94 +69,88 @@ export const useEnableDataFeed = () => {
const maxStartTime = date.setDate(date.getDate() - 14);

const datafeedId = `datafeed-${job.id}`;
if (enable) {
const startTime = Math.max(latestTimestampMs, maxStartTime);
const reportEnableJobError = (error: Error) => {
track(METRIC_TYPE.COUNT, TELEMETRY_EVENT.JOB_ENABLE_FAILURE);
addError(error, { title: i18n.START_JOB_FAILURE });
telemetry.reportMLJobUpdate({
jobId: job.id,
isElasticJob: job.isElasticJob,
status: ML_JOB_TELEMETRY_STATUS.startError,
errorMessage: `${i18n.START_JOB_FAILURE} - ${error.message}`,
});
};

try {
const response = await startDatafeeds({
datafeedIds: [datafeedId],
start: startTime,
});

if (response[datafeedId]?.error) {
throw new Error(response[datafeedId].error);
}
const startTime = Math.max(latestTimestampMs, maxStartTime);

telemetry.reportMLJobUpdate({
jobId: job.id,
isElasticJob: job.isElasticJob,
status: ML_JOB_TELEMETRY_STATUS.started,
});
try {
const response = await startDatafeeds({
datafeedIds: [datafeedId],
start: startTime,
});

return { enabled: response[datafeedId] ? response[datafeedId].started : false };
} catch (error) {
reportEnableJobError(error);
} finally {
setIsLoading(false);
if (response[datafeedId]?.error) {
throw new Error(response[datafeedId].error);
}
} else {
const reportDisableError = (error: Error) => {
track(METRIC_TYPE.COUNT, TELEMETRY_EVENT.JOB_DISABLE_FAILURE);
addError(error, { title: i18n.STOP_JOB_FAILURE });
telemetry.reportMLJobUpdate({
jobId: job.id,
isElasticJob: job.isElasticJob,
status: ML_JOB_TELEMETRY_STATUS.stopError,
errorMessage: `${i18n.STOP_JOB_FAILURE} - ${error.message}`,
});
};

try {
const [response] = await stopDatafeeds({ datafeedIds: [datafeedId] });
telemetry.reportMLJobUpdate({
jobId: job.id,
isElasticJob: job.isElasticJob,
status: ML_JOB_TELEMETRY_STATUS.started,
});

return { enabled: response[datafeedId] ? response[datafeedId].started : false };
} catch (error) {
track(METRIC_TYPE.COUNT, TELEMETRY_EVENT.JOB_ENABLE_FAILURE);
addError(error, { title: i18n.START_JOB_FAILURE });
telemetry.reportMLJobUpdate({
jobId: job.id,
isElasticJob: job.isElasticJob,
status: ML_JOB_TELEMETRY_STATUS.startError,
errorMessage: `${i18n.START_JOB_FAILURE} - ${error.message}`,
});
} finally {
setIsLoading(false);
}

if (isErrorResponse(response)) {
throw new Error(response.error);
}
return { enabled: false };
},
[addError, telemetry]
);

telemetry.reportMLJobUpdate({
jobId: job.id,
isElasticJob: job.isElasticJob,
status: ML_JOB_TELEMETRY_STATUS.stopped,
});
const disableDatafeed = useCallback(
async (job: SecurityJob) => {
track(
METRIC_TYPE.COUNT,
job.isElasticJob ? TELEMETRY_EVENT.SIEM_JOB_DISABLED : TELEMETRY_EVENT.CUSTOM_JOB_DISABLED
);
setIsLoading(true);

return { enabled: response[datafeedId] ? !response[datafeedId].stopped : true };
} catch (error) {
reportDisableError(error);
} finally {
setIsLoading(false);
const datafeedId = `datafeed-${job.id}`;

try {
const [response] = await stopDatafeeds({ datafeedIds: [datafeedId] });

if (isErrorResponse(response)) {
throw new Error(response.error);
}

telemetry.reportMLJobUpdate({
jobId: job.id,
isElasticJob: job.isElasticJob,
status: ML_JOB_TELEMETRY_STATUS.stopped,
});

return { enabled: response[datafeedId] ? !response[datafeedId].stopped : true };
} catch (error) {
track(METRIC_TYPE.COUNT, TELEMETRY_EVENT.JOB_DISABLE_FAILURE);
addError(error, { title: i18n.STOP_JOB_FAILURE });
telemetry.reportMLJobUpdate({
jobId: job.id,
isElasticJob: job.isElasticJob,
status: ML_JOB_TELEMETRY_STATUS.stopError,
errorMessage: `${i18n.STOP_JOB_FAILURE} - ${error.message}`,
});
} finally {
setIsLoading(false);
}
return { enabled: !enable };

return { enabled: true };
},
[addError, telemetry]
);

return { enableDatafeed, isLoading };
return { enableDatafeed, disableDatafeed, isLoading };
};

const isErrorResponse = (response: ErrorResponse): response is ErrorResponse =>
!isEmpty(response.error);

const submitTelemetry = (job: SecurityJob, enabled: boolean) => {
// Report type of job enabled/disabled
track(
METRIC_TYPE.COUNT,
job.isElasticJob
? enabled
? TELEMETRY_EVENT.SIEM_JOB_ENABLED
: TELEMETRY_EVENT.SIEM_JOB_DISABLED
: enabled
? TELEMETRY_EVENT.CUSTOM_JOB_ENABLED
: TELEMETRY_EVENT.CUSTOM_JOB_DISABLED
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -59,13 +59,22 @@ export const MlPopover = React.memo(() => {
} = useSecurityJobs();

const docLinks = useKibana().services.docLinks;
const { enableDatafeed, isLoading: isLoadingEnableDataFeed } = useEnableDataFeed();
const {
enableDatafeed,
disableDatafeed,
isLoading: isLoadingEnableDataFeed,
} = useEnableDataFeed();
const handleJobStateChange = useCallback(
async (job: SecurityJob, latestTimestampMs: number, enable: boolean) => {
await enableDatafeed(job, latestTimestampMs, enable);
if (enable) {
await enableDatafeed(job, latestTimestampMs);
} else {
await disableDatafeed(job);
}

refreshJobs();
},
[refreshJobs, enableDatafeed]
[refreshJobs, enableDatafeed, disableDatafeed]
);

const filteredJobs = filterJobs({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ export const useStartMlJobs = (): ReturnUseStartMlJobs => {
}

const latestTimestampMs = job.latestTimestampMs ?? 0;
await enableDatafeed(job, latestTimestampMs, true);
await enableDatafeed(job, latestTimestampMs);
})
);
refetchJobs();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,7 @@ describe('MlAdminJobDescription', () => {
userEvent.click(screen.getByTestId('job-switch'));
expect(enableDatafeedSpy).toHaveBeenCalledWith(
securityJobNotStarted,
securityJobNotStarted.latestTimestampMs,
true
securityJobNotStarted.latestTimestampMs
);

await waitFor(() => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,14 +25,23 @@ const MlAdminJobDescriptionComponent: FC<MlAdminJobDescriptionProps> = ({
loading,
refreshJob,
}) => {
const { enableDatafeed, isLoading: isLoadingEnableDataFeed } = useEnableDataFeed();
const {
enableDatafeed,
disableDatafeed,
isLoading: isLoadingEnableDataFeed,
} = useEnableDataFeed();

const handleJobStateChange = useCallback(
async (_, latestTimestampMs: number, enable: boolean) => {
await enableDatafeed(job, latestTimestampMs, enable);
if (enable) {
await enableDatafeed(job, latestTimestampMs);
} else {
await disableDatafeed(job);
}

refreshJob(job);
},
[enableDatafeed, job, refreshJob]
[enableDatafeed, disableDatafeed, job, refreshJob]
);

const switchComponent = useMemo(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ describe('EnableJob', () => {
fireEvent.click(getByText('Run job'));

await waitFor(() => {
expect(enableDatafeedMock).toHaveBeenCalledWith(job, job.latestTimestampMs, true);
expect(enableDatafeedMock).toHaveBeenCalledWith(job, job.latestTimestampMs);
expect(onJobEnabledMock).toHaveBeenCalledWith(job);
});
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ export const EnableJob = ({
const { enableDatafeed, isLoading: isEnabling } = useEnableDataFeed();

const handleChange = useCallback(async () => {
const result = await enableDatafeed(job, job.latestTimestampMs || 0, true);
const result = await enableDatafeed(job, job.latestTimestampMs || 0);

if (result.enabled) {
onJobEnabled(job);
Expand Down

0 comments on commit 9981451

Please sign in to comment.