[ML] Fix polling for notifications after leaving the ML app (#146203)

## Summary

Fixes notifications count polling on app leave. The issue was with the
`useMount` hook that doesn't support a callback execution on unmount.

### Checklist

- [x] [Unit or functional
tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)
were updated or added to match the most common scenarios
This commit is contained in:
Dima Arnautov 2022-11-24 15:08:33 +01:00 committed by GitHub
parent c9eebf262c
commit 93c594aa56
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 46 additions and 25 deletions

View file

@ -209,6 +209,25 @@ describe('useMlNotifications', () => {
expect(result.current.lastCheckedAt).toEqual(1664551009292);
});
test('stops fetching notifications on leave', () => {
const { unmount } = renderHook(useMlNotifications, {
wrapper: MlNotificationsContextProvider,
});
act(() => {
jest.advanceTimersByTime(0);
});
expect(mockCountMessages).toHaveBeenCalledTimes(1);
unmount();
act(() => {
jest.advanceTimersByTime(60001);
});
expect(mockCountMessages).toHaveBeenCalledTimes(1);
});
test('does not start polling if requires capabilities are missing', () => {
mockKibana.services.application.capabilities.ml = {
canGetJobs: true,

View file

@ -5,12 +5,11 @@
* 2.0.
*/
import React, { FC, useContext, useState } from 'react';
import React, { FC, useContext, useState, useEffect } from 'react';
import { combineLatest, timer } from 'rxjs';
import { switchMap, map, tap, retry } from 'rxjs/operators';
import moment from 'moment';
import { isPopulatedObject } from '@kbn/ml-is-populated-object';
import useMount from 'react-use/lib/useMount';
import { useMlKibana } from '../kibana';
import { useStorage } from '../storage';
import { ML_NOTIFICATIONS_LAST_CHECKED_AT } from '../../../../common/types/storage';
@ -56,31 +55,34 @@ export const MlNotificationsContextProvider: FC = ({ children }) => {
const [notificationsCounts, setNotificationsCounts] =
useState<NotificationsCountResponse>(defaultCounts);
useMount(function startPollingNotifications() {
if (!canGetNotifications) return;
useEffect(
function startPollingNotifications() {
if (!canGetNotifications) return;
const subscription = combineLatest([lastCheckedAt$, timer(0, NOTIFICATIONS_CHECK_INTERVAL)])
.pipe(
// Use the latest check time or 7 days ago by default.
map(([lastChecked]) => lastChecked ?? moment().subtract(7, 'd').valueOf()),
tap((lastCheckedAtQuery) => {
setLatestRequestedAt(lastCheckedAtQuery);
}),
switchMap((lastCheckedAtQuery) =>
mlApiServices.notifications.countMessages$({
lastCheckedAt: lastCheckedAtQuery,
})
),
retry({ delay: NOTIFICATIONS_CHECK_INTERVAL })
)
.subscribe((response) => {
setNotificationsCounts(isPopulatedObject(response) ? response : defaultCounts);
});
const subscription = combineLatest([lastCheckedAt$, timer(0, NOTIFICATIONS_CHECK_INTERVAL)])
.pipe(
// Use the latest check time or 7 days ago by default.
map(([lastChecked]) => lastChecked ?? moment().subtract(7, 'd').valueOf()),
tap((lastCheckedAtQuery) => {
setLatestRequestedAt(lastCheckedAtQuery);
}),
switchMap((lastCheckedAtQuery) =>
mlApiServices.notifications.countMessages$({
lastCheckedAt: lastCheckedAtQuery,
})
),
retry({ delay: NOTIFICATIONS_CHECK_INTERVAL })
)
.subscribe((response) => {
setNotificationsCounts(isPopulatedObject(response) ? response : defaultCounts);
});
return () => {
subscription.unsubscribe();
};
});
return () => {
subscription.unsubscribe();
};
},
[canGetNotifications, lastCheckedAt$, mlApiServices.notifications]
);
return (
<MlNotificationsContext.Provider