2
0
mirror of https://github.com/hibiken/asynqmon.git synced 2025-10-26 16:26:12 +08:00

Add redux actions/reducer for metrics

This commit is contained in:
Ken Hibino
2021-11-27 07:20:12 -08:00
parent 0279bd29cd
commit d60905334f
15 changed files with 483 additions and 8 deletions

View File

@@ -0,0 +1,45 @@
import { Dispatch } from "redux";
import { getMetrics, MetricsResponse } from "../api";
import { toErrorString, toErrorStringWithHttpStatus } from "../utils";
// List of metrics related action types.
export const GET_METRICS_BEGIN = "GET_METRICS_BEGIN";
export const GET_METRICS_SUCCESS = "GET_METRICS_SUCCESS";
export const GET_METRICS_ERROR = "GET_METRICS_ERROR";
interface GetMetricsBeginAction {
type: typeof GET_METRICS_BEGIN;
}
interface GetMetricsSuccessAction {
type: typeof GET_METRICS_SUCCESS;
payload: MetricsResponse;
}
interface GetMetricsErrorAction {
type: typeof GET_METRICS_ERROR;
error: string;
}
// Union of all metrics related actions.
export type MetricsActionTypes =
| GetMetricsBeginAction
| GetMetricsSuccessAction
| GetMetricsErrorAction;
export function getMetricsAsync() {
return async (dispatch: Dispatch<MetricsActionTypes>) => {
dispatch({ type: GET_METRICS_BEGIN });
try {
const response = await getMetrics();
console.log("DEBUG: got metrics: ", response);
dispatch({ type: GET_METRICS_SUCCESS, payload: response });
} catch (error) {
console.error(`getMetricsAsync: ${toErrorStringWithHttpStatus(error)}`);
dispatch({
type: GET_METRICS_ERROR,
error: toErrorString(error),
});
}
};
}

View File

@@ -76,6 +76,27 @@ export interface QueueLocation {
nodes: string[]; // node addresses
}
export interface MetricsResponse {
data: MetricsResult;
}
export interface MetricsResult {
result: Metrics[];
}
export interface Metrics {
metric: MetricsInfo;
values: [number, string]; // [unixtime, value]
}
export interface MetricsInfo {
__name__: string;
instance: string;
job: string;
queue: string;
state: string;
}
// Return value from redis INFO command.
// See https://redis.io/commands/info#return-value.
export interface RedisInfo {
@@ -854,3 +875,11 @@ export async function getRedisInfo(): Promise<RedisInfoResponse> {
});
return resp.data;
}
export async function getMetrics(): Promise<MetricsResponse> {
const resp = await axios({
method: "get",
url: `${BASE_URL}/metrics`,
});
return resp.data;
}

View File

@@ -0,0 +1,49 @@
import {
GET_METRICS_BEGIN,
GET_METRICS_ERROR,
GET_METRICS_SUCCESS,
MetricsActionTypes,
} from "../actions/metricsActions";
import { MetricsResponse } from "../api";
interface MetricsState {
loading: boolean;
error: string;
data: MetricsResponse | null;
}
const initialState: MetricsState = {
loading: false,
error: "",
data: null,
};
export default function metricsReducer(
state = initialState,
action: MetricsActionTypes
): MetricsState {
switch (action.type) {
case GET_METRICS_BEGIN:
return {
...state,
loading: true,
};
case GET_METRICS_ERROR:
return {
...state,
loading: false,
error: action.error,
};
case GET_METRICS_SUCCESS:
return {
loading: false,
error: "",
data: action.payload,
};
default:
return state;
}
}

View File

@@ -7,6 +7,7 @@ import schedulerEntriesReducer from "./reducers/schedulerEntriesReducer";
import snackbarReducer from "./reducers/snackbarReducer";
import queueStatsReducer from "./reducers/queueStatsReducer";
import redisInfoReducer from "./reducers/redisInfoReducer";
import metricsReducer from "./reducers/metricsReducer";
import { loadState } from "./localStorage";
const rootReducer = combineReducers({
@@ -18,6 +19,7 @@ const rootReducer = combineReducers({
snackbar: snackbarReducer,
queueStats: queueStatsReducer,
redis: redisInfoReducer,
metrics: metricsReducer,
});
const preloadedState = loadState();

View File

@@ -1,4 +1,4 @@
import { createMuiTheme, Theme } from "@material-ui/core/styles";
import { createTheme, Theme } from "@material-ui/core/styles";
import { ThemePreference } from "./reducers/settingsReducer";
import useMediaQuery from "@material-ui/core/useMediaQuery";
@@ -9,7 +9,7 @@ export function useTheme(themePreference: ThemePreference): Theme {
} else if (themePreference === ThemePreference.Never) {
prefersDarkMode = false;
}
return createMuiTheme({
return createTheme({
// Got color palette from https://htmlcolors.com/palette/31/stripe
palette: {
primary: {

View File

@@ -1,7 +1,11 @@
import React, { useEffect } from "react";
import { connect, ConnectedProps } from "react-redux";
import { makeStyles } from "@material-ui/core/styles";
import Container from "@material-ui/core/Container";
import Grid from "@material-ui/core/Grid";
import { getMetricsAsync } from "../actions/metricsActions";
import { AppState } from "../store";
import { usePolling } from "../hooks";
const useStyles = makeStyles((theme) => ({
container: {
@@ -10,12 +14,23 @@ const useStyles = makeStyles((theme) => ({
},
}));
function MetricsView() {
const classes = useStyles();
function mapStateToProps(state: AppState) {
return {
loading: state.metrics.loading,
error: state.metrics.error,
data: state.metrics.data,
pollInterval: state.settings.pollInterval,
};
}
useEffect(() => {
console.log("TODO: Get metrics data!");
}, []);
const connector = connect(mapStateToProps, { getMetricsAsync });
type Props = ConnectedProps<typeof connector>;
function MetricsView(props: Props) {
const classes = useStyles();
const { pollInterval, getMetricsAsync } = props;
usePolling(getMetricsAsync, pollInterval);
return (
<Container maxWidth="lg" className={classes.container}>
@@ -28,4 +43,4 @@ function MetricsView() {
);
}
export default MetricsView;
export default connector(MetricsView);