From 4951d2f571cb14be41f866481e25e0a4ebc5114a Mon Sep 17 00:00:00 2001 From: Ken Hibino Date: Sun, 3 Jan 2021 08:07:19 -0800 Subject: [PATCH] Fetch redis info from RedisInfoView --- ui/src/actions/redisInfoActions.ts | 43 +++++++++ ui/src/api.ts | 143 ++++++++++++++++++++++++++++ ui/src/reducers/redisInfoReducer.ts | 45 +++++++++ ui/src/store.ts | 2 + ui/src/views/RedisInfoView.tsx | 22 ++++- 5 files changed, 253 insertions(+), 2 deletions(-) create mode 100644 ui/src/actions/redisInfoActions.ts create mode 100644 ui/src/reducers/redisInfoReducer.ts diff --git a/ui/src/actions/redisInfoActions.ts b/ui/src/actions/redisInfoActions.ts new file mode 100644 index 0000000..d05b7fc --- /dev/null +++ b/ui/src/actions/redisInfoActions.ts @@ -0,0 +1,43 @@ +import { Dispatch } from "redux"; +import { getRedisInfo, RedisInfo } from "../api"; + +// List of redis-info related action types. +export const GET_REDIS_INFO_BEGIN = "GET_REDIS_INFO_BEGIN"; +export const GET_REDIS_INFO_SUCCESS = "GET_REDIS_INFO_SUCCESS"; +export const GET_REDIS_INFO_ERROR = "GET_REDIS_INFO_ERROR"; + +interface GetRedisInfoBeginAction { + type: typeof GET_REDIS_INFO_BEGIN; +} + +interface GetRedisInfoSuccessAction { + type: typeof GET_REDIS_INFO_SUCCESS; + payload: RedisInfo; +} + +interface GetRedisInfoErrorAction { + type: typeof GET_REDIS_INFO_ERROR; + error: string; +} + +// Union of all redis-info related actions. +export type RedisInfoActionTypes = + | GetRedisInfoBeginAction + | GetRedisInfoErrorAction + | GetRedisInfoSuccessAction; + +export function getRedisInfoAsync() { + return async (dispatch: Dispatch) => { + dispatch({ type: GET_REDIS_INFO_BEGIN }); + try { + const response = await getRedisInfo(); + dispatch({ type: GET_REDIS_INFO_SUCCESS, payload: response }); + } catch (error) { + console.error("getRedisInfoAsync: ", error); + dispatch({ + type: GET_REDIS_INFO_BEGIN, + error: "Could not fetch redis info", + }); + } + }; +} diff --git a/ui/src/api.ts b/ui/src/api.ts index 92065b0..cfc7d29 100644 --- a/ui/src/api.ts +++ b/ui/src/api.ts @@ -68,6 +68,141 @@ export interface ListQueueStatsResponse { stats: { [qname: string]: DailyStat[] }; } +// Return value from redis INFO command. +// See https://redis.io/commands/info#return-value. +export interface RedisInfo { + active_defrag_hits: string; + active_defrag_key_hits: string; + active_defrag_key_misses: string; + active_defrag_misses: string; + active_defrag_running: string; + allocator_active: string; + allocator_allocated: string; + allocator_frag_bytes: string; + allocator_frag_ratio: string; + allocator_resident: string; + allocator_rss_bytes: string; + allocator_rss_ratio: string; + aof_current_rewrite_time_sec: string; + aof_enabled: string; + aof_last_bgrewrite_status: string; + aof_last_cow_size: string; + aof_last_rewrite_time_sec: string; + aof_last_write_status: string; + aof_rewrite_in_progress: string; + aof_rewrite_scheduled: string; + arch_bits: string; + atomicvar_api: string; + blocked_clients: string; + client_recent_max_input_buffer: string; + client_recent_max_output_buffer: string; + clients_in_timeout_table: string; + cluster_enabled: string; + config_file: string; + configured_hz: string; + connected_clients: string; + connected_slaves: string; + evicted_keys: string; + executable: string; + expire_cycle_cpu_milliseconds: string; + expired_keys: string; + expired_stale_perc: string; + expired_time_cap_reached_count: string; + gcc_version: string; + hz: string; + instantaneous_input_kbps: string; + instantaneous_ops_per_sec: string; + instantaneous_output_kbps: string; + keyspace_hits: string; + keyspace_misses: string; + latest_fork_usec: string; + lazyfree_pending_objects: string; + loading: string; + lru_clock: string; + master_repl_offset: string; + master_replid: string; + master_replid2: string; + maxmemory: string; + maxmemory_human: string; + maxmemory_policy: string; + mem_allocator: string; + mem_aof_buffer: string; + mem_clients_normal: string; + mem_clients_slaves: string; + mem_fragmentation_bytes: string; + mem_fragmentation_ratio: string; + mem_not_counted_for_evict: string; + mem_replication_backlog: string; + migrate_cached_sockets: string; + module_fork_in_progress: string; + module_fork_last_cow_size: string; + multiplexing_api: string; + number_of_cached_scripts: string; + os: string; + process_id: string; + pubsub_channels: string; + pubsub_patterns: string; + rdb_bgsave_in_progress: string; + rdb_changes_since_last_save: string; + rdb_current_bgsave_time_sec: string; + rdb_last_bgsave_status: string; + rdb_last_bgsave_time_sec: string; + rdb_last_cow_size: string; + rdb_last_save_time: string; + redis_build_id: string; + redis_git_dirty: string; + redis_git_sha1: string; + redis_mode: string; + redis_version: string; + rejected_connections: string; + repl_backlog_active: string; + repl_backlog_first_byte_offset: string; + repl_backlog_histlen: string; + repl_backlog_size: string; + role: string; + rss_overhead_bytes: string; + rss_overhead_ratio: string; + run_id: string; + second_repl_offset: string; + slave_expires_tracked_keys: string; + sync_full: string; + sync_partial_err: string; + sync_partial_ok: string; + tcp_port: string; + total_commands_processed: string; + total_connections_received: string; + total_net_input_bytes: string; + total_net_output_bytes: string; + total_system_memory: string; + total_system_memory_human: string; + tracking_clients: string; + tracking_total_items: string; + tracking_total_keys: string; + tracking_total_prefixes: string; + unexpected_error_replies: string; + uptime_in_days: string; + uptime_in_seconds: string; + used_cpu_sys: string; + used_cpu_sys_children: string; + used_cpu_user: string; + used_cpu_user_children: string; + used_memory: string; + used_memory_dataset: string; + used_memory_dataset_perc: string; + used_memory_human: string; + used_memory_lua: string; + used_memory_lua_human: string; + used_memory_overhead: string; + used_memory_peak: string; + used_memory_peak_human: string; + used_memory_peak_perc: string; + used_memory_rss: string; + used_memory_rss_human: string; + used_memory_scripts: string; + used_memory_scripts_human: string; + used_memory_startup: string; +} + export interface Queue { queue: string; paused: boolean; @@ -587,3 +722,11 @@ export async function listSchedulerEnqueueEvents( }); return resp.data; } + +export async function getRedisInfo(): Promise { + const resp = await axios({ + method: "get", + url: `${BASE_URL}/redis_info`, + }); + return resp.data; +} diff --git a/ui/src/reducers/redisInfoReducer.ts b/ui/src/reducers/redisInfoReducer.ts new file mode 100644 index 0000000..3129e58 --- /dev/null +++ b/ui/src/reducers/redisInfoReducer.ts @@ -0,0 +1,45 @@ +import { + GET_REDIS_INFO_BEGIN, + GET_REDIS_INFO_ERROR, + GET_REDIS_INFO_SUCCESS, + RedisInfoActionTypes, +} from "../actions/redisInfoActions"; +import { RedisInfo } from "../api"; + +interface RedisInfoState { + loading: boolean; + data: RedisInfo | null; +} + +const initialState: RedisInfoState = { + loading: false, + data: null, +}; + +export default function redisInfoReducer( + state = initialState, + action: RedisInfoActionTypes +): RedisInfoState { + switch (action.type) { + case GET_REDIS_INFO_BEGIN: + return { + ...state, + loading: true, + }; + + case GET_REDIS_INFO_ERROR: + return { + ...state, + loading: false, + }; + + case GET_REDIS_INFO_SUCCESS: + return { + loading: false, + data: action.payload, + }; + + default: + return state; + } +} diff --git a/ui/src/store.ts b/ui/src/store.ts index 3c781f1..f8017d1 100644 --- a/ui/src/store.ts +++ b/ui/src/store.ts @@ -6,6 +6,7 @@ import serversReducer from "./reducers/serversReducer"; import schedulerEntriesReducer from "./reducers/schedulerEntriesReducer"; import snackbarReducer from "./reducers/snackbarReducer"; import queueStatsReducer from "./reducers/queueStatsReducer"; +import redisInfoReducer from "./reducers/redisInfoReducer"; const rootReducer = combineReducers({ settings: settingsReducer, @@ -15,6 +16,7 @@ const rootReducer = combineReducers({ schedulerEntries: schedulerEntriesReducer, snackbar: snackbarReducer, queueStats: queueStatsReducer, + redis: redisInfoReducer, }); // AppState is the top-level application state maintained by redux store. diff --git a/ui/src/views/RedisInfoView.tsx b/ui/src/views/RedisInfoView.tsx index 0d68671..b8bb1ae 100644 --- a/ui/src/views/RedisInfoView.tsx +++ b/ui/src/views/RedisInfoView.tsx @@ -1,8 +1,12 @@ import React from "react"; +import { connect, ConnectedProps } from "react-redux"; import Container from "@material-ui/core/Container"; import { makeStyles } from "@material-ui/core/styles"; import Grid from "@material-ui/core/Grid"; import Typography from "@material-ui/core/Typography"; +import { getRedisInfoAsync } from "../actions/redisInfoActions"; +import { usePolling } from "../hooks"; +import { AppState } from "../store"; const useStyles = makeStyles((theme) => ({ container: { @@ -17,8 +21,22 @@ const useStyles = makeStyles((theme) => ({ }, })); -function RedisInfoView() { +function mapStateToProps(state: AppState) { + return { + loading: state.redis.loading, + redisInfo: state.redis.data, + pollInterval: state.settings.pollInterval, + }; +} + +const connector = connect(mapStateToProps, { getRedisInfoAsync }); +type Props = ConnectedProps; + +function RedisInfoView(props: Props) { const classes = useStyles(); + const { pollInterval, getRedisInfoAsync } = props; + + usePolling(getRedisInfoAsync, pollInterval); return ( @@ -31,4 +49,4 @@ function RedisInfoView() { ); } -export default RedisInfoView; +export default connector(RedisInfoView);