diff --git a/src/actions/heartbeat.ts b/src/actions/heartbeat.ts new file mode 100644 index 000000000..2db9a8a5b --- /dev/null +++ b/src/actions/heartbeat.ts @@ -0,0 +1,14 @@ +import { HEARTBEAT_REQUEST, HEARTBEAT_RESPONSE } from "@src/constants"; + +export function heartbeatRequest(): { + type: "HEARTBEAT_REQUEST"; +} { + return { type: HEARTBEAT_REQUEST }; +} + +export function heartbeatResponse(response: Record): { + type: "HEARTBEAT_RESPONSE"; + response: Record; +} { + return { type: HEARTBEAT_RESPONSE, response }; +} diff --git a/src/components/SessionInfoBar.tsx b/src/components/SessionInfoBar.tsx index f36bfeffc..fde0d1c9a 100644 --- a/src/components/SessionInfoBar.tsx +++ b/src/components/SessionInfoBar.tsx @@ -1,7 +1,7 @@ +import * as HeartbeatActions from "@src/actions/heartbeat"; import * as SessionActions from "@src/actions/session"; -import { getClient } from "@src/client"; import { useAppDispatch, useAppSelector } from "@src/hooks/app"; -import React, { useEffect, useState } from "react"; +import React, { useEffect } from "react"; import { BoxArrowRight, CircleFill, @@ -11,31 +11,19 @@ import { } from "react-bootstrap-icons"; export function SessionInfoBar() { - const { url, project_name, project_docs, user } = useAppSelector( - store => store.session.serverInfo + const { heartbeat, url, project_name, project_docs, user } = useAppSelector( + store => { + return { + ...store.session.serverInfo, + heartbeat: store.heartbeat, + }; + } ); const dispatch = useAppDispatch(); - const [isHealthy, setIsHealthy] = useState(true); - const client = getClient(); const checkHeartbeat = async () => { - try { - let response: Record = await client.execute({ - path: "/__heartbeat__", - headers: undefined, - }); - for (let prop in response) { - if (response[prop] === false) { - setIsHealthy(false); - return; - } - } - setIsHealthy(true); - } catch (ex) { - setIsHealthy(false); - } finally { - setTimeout(checkHeartbeat, 60000); - } + dispatch(HeartbeatActions.heartbeatRequest()); + setTimeout(checkHeartbeat, 60000); }; useEffect(() => { @@ -67,7 +55,7 @@ export function SessionInfoBar() { - {isHealthy ? ( + {heartbeat.success !== false ? ( ) { bucket, collection, group, + heartbeat, record, notifications, servers, diff --git a/src/sagas/heartbeat.ts b/src/sagas/heartbeat.ts new file mode 100644 index 000000000..ab18be264 --- /dev/null +++ b/src/sagas/heartbeat.ts @@ -0,0 +1,39 @@ +import * as actions from "@src/actions/heartbeat"; +import { getClient } from "@src/client"; +import { ActionType, GetStateFn, SagaGen } from "@src/types"; +import { call, put } from "redux-saga/effects"; + +export function* heartbeatRequest( + getState: GetStateFn, + action: ActionType +): SagaGen { + const response = yield call(queryHeartbeat); + yield put(actions.heartbeatResponse(response)); +} + +async function queryHeartbeat(): Promise> { + const client = getClient(); + + try { + const response: Record = await client.execute({ + path: "/__heartbeat__", + headers: undefined, + }); + let success = true; + for (let prop in response) { + if (response[prop] === false) { + success = false; + break; + } + } + return { + success, + response, + }; + } catch (ex) { + return { + success: false, + details: ex, + }; + } +} diff --git a/src/sagas/index.ts b/src/sagas/index.ts index 92c06ec5b..f6e82ed17 100644 --- a/src/sagas/index.ts +++ b/src/sagas/index.ts @@ -1,6 +1,7 @@ import * as bucketSagas from "./bucket"; import * as collectionSagas from "./collection"; import * as groupSagas from "./group"; +import * as heartbeatSagas from "./heartbeat"; import * as recordSagas from "./record"; import * as routeSagas from "./route"; import * as sessionSagas from "./session"; @@ -143,6 +144,8 @@ export default function* rootSaga(getState: GetStateFn): SagaGen { signoffSagas.handleApproveChanges, getState ), + // heartbeat + takeEvery(c.HEARTBEAT_REQUEST, heartbeatSagas.heartbeatRequest, getState), ]; yield all(sagas); diff --git a/src/types.ts b/src/types.ts index 34eff49a8..8f08c03a1 100644 --- a/src/types.ts +++ b/src/types.ts @@ -529,3 +529,8 @@ export type DestinationInfo = { bid: string; cid: string; }; + +export type HeartbeatState = { + success: boolean; + response: Record; +};