mirror of
https://github.com/prometheus/prometheus.git
synced 2024-12-26 22:19:40 -08:00
Retry SSE connection unless max clients have been reached.
This switches from the prehistoric EventSource API to the more modern fetch-event-source package. That packages gives us full control over the retries. It also gives us the opportunity to close the event source when the browser tab is hidden, saving resources. Signed-off-by: Julien <roidelapluie@o11y.eu>
This commit is contained in:
parent
f9bbad1148
commit
e34563bfe0
|
@ -1704,6 +1704,10 @@ func (api *API) notificationsSSE(w http.ResponseWriter, r *http.Request) {
|
|||
return
|
||||
}
|
||||
|
||||
// Flush the response to ensure the headers are immediately and eventSource
|
||||
// onopen is triggered client-side.
|
||||
flusher.Flush()
|
||||
|
||||
for {
|
||||
select {
|
||||
case notification := <-notifications:
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
"@mantine/dates": "^7.11.2",
|
||||
"@mantine/hooks": "^7.11.2",
|
||||
"@mantine/notifications": "^7.11.2",
|
||||
"@microsoft/fetch-event-source": "^2.0.1",
|
||||
"@nexucis/fuzzy": "^0.5.1",
|
||||
"@nexucis/kvsearch": "^0.9.1",
|
||||
"@prometheus-io/codemirror-promql": "0.300.0-beta.0",
|
||||
|
|
|
@ -3,6 +3,7 @@ import { useSettings } from '../state/settingsSlice';
|
|||
import { NotificationsContext } from '../state/useNotifications';
|
||||
import { Notification, NotificationsResult } from "../api/responseTypes/notifications";
|
||||
import { useAPIQuery } from '../api/api';
|
||||
import { fetchEventSource } from '@microsoft/fetch-event-source';
|
||||
|
||||
export const NotificationsProvider: React.FC<{ children: React.ReactNode }> = ({ children }) => {
|
||||
const { pathPrefix } = useSettings();
|
||||
|
@ -24,31 +25,47 @@ export const NotificationsProvider: React.FC<{ children: React.ReactNode }> = ({
|
|||
}, [data, isError]);
|
||||
|
||||
useEffect(() => {
|
||||
const eventSource = new EventSource(`${pathPrefix}/api/v1/notifications/live`);
|
||||
|
||||
eventSource.onmessage = (event) => {
|
||||
const notification: Notification = JSON.parse(event.data);
|
||||
|
||||
setNotifications((prev: Notification[]) => {
|
||||
const updatedNotifications = [...prev.filter((n: Notification) => n.text !== notification.text)];
|
||||
|
||||
if (notification.active) {
|
||||
updatedNotifications.push(notification);
|
||||
const controller = new AbortController();
|
||||
fetchEventSource(`${pathPrefix}/api/v1/notifications/live`, {
|
||||
signal: controller.signal,
|
||||
async onopen(response) {
|
||||
if (response.ok) {
|
||||
if (response.status === 200) {
|
||||
setNotifications([]);
|
||||
setIsConnectionError(false);
|
||||
} else if (response.status === 204) {
|
||||
controller.abort();
|
||||
setShouldFetchFromAPI(true);
|
||||
}
|
||||
} else {
|
||||
setIsConnectionError(true);
|
||||
throw new Error(`Unexpected response: ${response.status} ${response.statusText}`);
|
||||
}
|
||||
},
|
||||
onmessage(event) {
|
||||
const notification: Notification = JSON.parse(event.data);
|
||||
|
||||
return updatedNotifications;
|
||||
});
|
||||
};
|
||||
setNotifications((prev: Notification[]) => {
|
||||
const updatedNotifications = [...prev.filter((n: Notification) => n.text !== notification.text)];
|
||||
|
||||
eventSource.onerror = () => {
|
||||
eventSource.close();
|
||||
// We do not call setIsConnectionError(true), we only set it to true if
|
||||
// the fallback API does not work either.
|
||||
setShouldFetchFromAPI(true);
|
||||
};
|
||||
if (notification.active) {
|
||||
updatedNotifications.push(notification);
|
||||
}
|
||||
|
||||
return updatedNotifications;
|
||||
});
|
||||
},
|
||||
onclose() {
|
||||
throw new Error("Server closed the connection");
|
||||
},
|
||||
onerror() {
|
||||
setIsConnectionError(true);
|
||||
return 5000;
|
||||
},
|
||||
});
|
||||
|
||||
return () => {
|
||||
eventSource.close();
|
||||
controller.abort();
|
||||
};
|
||||
}, [pathPrefix]);
|
||||
|
||||
|
|
6
web/ui/package-lock.json
generated
6
web/ui/package-lock.json
generated
|
@ -39,6 +39,7 @@
|
|||
"@mantine/dates": "^7.11.2",
|
||||
"@mantine/hooks": "^7.11.2",
|
||||
"@mantine/notifications": "^7.11.2",
|
||||
"@microsoft/fetch-event-source": "^2.0.1",
|
||||
"@nexucis/fuzzy": "^0.5.1",
|
||||
"@nexucis/kvsearch": "^0.9.1",
|
||||
"@prometheus-io/codemirror-promql": "0.300.0-beta.0",
|
||||
|
@ -2255,6 +2256,11 @@
|
|||
"react": "^18.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@microsoft/fetch-event-source": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@microsoft/fetch-event-source/-/fetch-event-source-2.0.1.tgz",
|
||||
"integrity": "sha512-W6CLUJ2eBMw3Rec70qrsEW0jOm/3twwJv21mrmj2yORiaVmVYGS4sSS5yUwvQc1ZlDLYGPnClVWmUUMagKNsfA=="
|
||||
},
|
||||
"node_modules/@nexucis/fuzzy": {
|
||||
"version": "0.5.1",
|
||||
"resolved": "https://registry.npmjs.org/@nexucis/fuzzy/-/fuzzy-0.5.1.tgz",
|
||||
|
|
Loading…
Reference in a new issue