mirror of
https://github.com/hibiken/asynqmon.git
synced 2025-01-19 03:05:53 +08:00
Fetch servers info and show in ServersTable
This commit is contained in:
parent
d78abcf584
commit
3f9e8820d9
44
ui/src/actions/serversActions.ts
Normal file
44
ui/src/actions/serversActions.ts
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
import { Dispatch } from "redux";
|
||||||
|
import { listServers, ListServersResponse } from "../api";
|
||||||
|
|
||||||
|
// List of server related action types.
|
||||||
|
export const LIST_SERVERS_BEGIN = "LIST_SERVERS_BEGIN";
|
||||||
|
export const LIST_SERVERS_SUCCESS = "LIST_SERVERS_SUCCESS";
|
||||||
|
export const LIST_SERVERS_ERROR = "LIST_SERVERS_ERROR";
|
||||||
|
|
||||||
|
interface ListServersBeginAction {
|
||||||
|
type: typeof LIST_SERVERS_BEGIN;
|
||||||
|
}
|
||||||
|
interface ListServersSuccessAction {
|
||||||
|
type: typeof LIST_SERVERS_SUCCESS;
|
||||||
|
payload: ListServersResponse;
|
||||||
|
}
|
||||||
|
interface ListServersErrorAction {
|
||||||
|
type: typeof LIST_SERVERS_ERROR;
|
||||||
|
error: string; // error description
|
||||||
|
}
|
||||||
|
|
||||||
|
// Union of all server related actions.
|
||||||
|
export type ServersActionTypes =
|
||||||
|
| ListServersBeginAction
|
||||||
|
| ListServersSuccessAction
|
||||||
|
| ListServersErrorAction;
|
||||||
|
|
||||||
|
export function listServersAsync() {
|
||||||
|
return async (dispatch: Dispatch<ServersActionTypes>) => {
|
||||||
|
dispatch({ type: LIST_SERVERS_BEGIN });
|
||||||
|
try {
|
||||||
|
const response = await listServers();
|
||||||
|
dispatch({
|
||||||
|
type: LIST_SERVERS_SUCCESS,
|
||||||
|
payload: response,
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
console.error("listServersAsync: ", error);
|
||||||
|
dispatch({
|
||||||
|
type: LIST_SERVERS_ERROR,
|
||||||
|
error: "Could not retrieve servers info",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
@ -32,6 +32,10 @@ export interface ListDeadTasksResponse {
|
|||||||
stats: Queue;
|
stats: Queue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface ListServersResponse {
|
||||||
|
servers: ServerInfo[];
|
||||||
|
}
|
||||||
|
|
||||||
export interface ListSchedulerEntriesResponse {
|
export interface ListSchedulerEntriesResponse {
|
||||||
entries: SchedulerEntry[];
|
entries: SchedulerEntry[];
|
||||||
}
|
}
|
||||||
@ -129,7 +133,20 @@ export interface DeadTask extends BaseTask {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface ServerInfo {
|
export interface ServerInfo {
|
||||||
// TODO: fill this out
|
id: string;
|
||||||
|
host: string;
|
||||||
|
pid: number;
|
||||||
|
concurrency: number;
|
||||||
|
queue_priorities: { [qname: string]: number };
|
||||||
|
strict_priority_enabled: boolean;
|
||||||
|
start_time: string;
|
||||||
|
status: string;
|
||||||
|
active_workers: WorkerInfo[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface WorkerInfo {
|
||||||
|
task: ActiveTask;
|
||||||
|
start_time: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface SchedulerEntry {
|
export interface SchedulerEntry {
|
||||||
@ -545,6 +562,14 @@ export async function runAllDeadTasks(qname: string): Promise<void> {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function listServers(): Promise<ListServersResponse> {
|
||||||
|
const resp = await axios({
|
||||||
|
method: "get",
|
||||||
|
url: `${BASE_URL}/servers`,
|
||||||
|
});
|
||||||
|
return resp.data;
|
||||||
|
}
|
||||||
|
|
||||||
export async function listSchedulerEntries(): Promise<ListSchedulerEntriesResponse> {
|
export async function listSchedulerEntries(): Promise<ListSchedulerEntriesResponse> {
|
||||||
const resp = await axios({
|
const resp = await axios({
|
||||||
method: "get",
|
method: "get",
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
import React, { useState } from "react";
|
import React, { useState } from "react";
|
||||||
import clsx from "clsx";
|
import clsx from "clsx";
|
||||||
import { makeStyles } from "@material-ui/core/styles";
|
import { makeStyles } from "@material-ui/core/styles";
|
||||||
import IconButton from "@material-ui/core/IconButton";
|
|
||||||
import Table from "@material-ui/core/Table";
|
import Table from "@material-ui/core/Table";
|
||||||
import TableBody from "@material-ui/core/TableBody";
|
import TableBody from "@material-ui/core/TableBody";
|
||||||
import TableCell from "@material-ui/core/TableCell";
|
import TableCell from "@material-ui/core/TableCell";
|
||||||
@ -13,6 +12,7 @@ import Alert from "@material-ui/lab/Alert";
|
|||||||
import AlertTitle from "@material-ui/lab/AlertTitle";
|
import AlertTitle from "@material-ui/lab/AlertTitle";
|
||||||
import { ServerInfo } from "../api";
|
import { ServerInfo } from "../api";
|
||||||
import { SortDirection, SortableTableColumn } from "../types/table";
|
import { SortDirection, SortableTableColumn } from "../types/table";
|
||||||
|
import { timeAgo } from "../utils";
|
||||||
|
|
||||||
const useStyles = makeStyles((theme) => ({
|
const useStyles = makeStyles((theme) => ({
|
||||||
table: {
|
table: {
|
||||||
@ -140,8 +140,43 @@ export default function ServersTable(props: Props) {
|
|||||||
))}
|
))}
|
||||||
</TableRow>
|
</TableRow>
|
||||||
</TableHead>
|
</TableHead>
|
||||||
<TableBody></TableBody>
|
<TableBody>
|
||||||
|
{sortServerInfos(props.servers, cmpFunc).map((srv) => (
|
||||||
|
<Row key={srv.id} server={srv} />
|
||||||
|
))}
|
||||||
|
</TableBody>
|
||||||
</Table>
|
</Table>
|
||||||
</TableContainer>
|
</TableContainer>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
interface RowProps {
|
||||||
|
server: ServerInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
const useRowStyles = makeStyles((theme) => ({
|
||||||
|
rowRoot: {
|
||||||
|
"& > *": {
|
||||||
|
borderBottom: "unset",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
noBorder: {
|
||||||
|
border: "none",
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
|
||||||
|
function Row(props: RowProps) {
|
||||||
|
const classes = useRowStyles();
|
||||||
|
const { server } = props;
|
||||||
|
return (
|
||||||
|
<TableRow className={classes.rowRoot}>
|
||||||
|
<TableCell>{server.host}</TableCell>
|
||||||
|
<TableCell>{server.pid}</TableCell>
|
||||||
|
<TableCell>{server.status}</TableCell>
|
||||||
|
<TableCell>
|
||||||
|
{server.active_workers.length}/{server.concurrency}
|
||||||
|
</TableCell>
|
||||||
|
<TableCell>{JSON.stringify(server.queue_priorities)}</TableCell>
|
||||||
|
<TableCell>{timeAgo(server.start_time)}</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
45
ui/src/reducers/serversReducer.ts
Normal file
45
ui/src/reducers/serversReducer.ts
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
import {
|
||||||
|
LIST_SERVERS_BEGIN,
|
||||||
|
LIST_SERVERS_ERROR,
|
||||||
|
LIST_SERVERS_SUCCESS,
|
||||||
|
ServersActionTypes,
|
||||||
|
} from "../actions/serversActions";
|
||||||
|
import { ServerInfo } from "../api";
|
||||||
|
|
||||||
|
interface ServersState {
|
||||||
|
loading: boolean;
|
||||||
|
data: ServerInfo[];
|
||||||
|
}
|
||||||
|
|
||||||
|
const initialState: ServersState = {
|
||||||
|
loading: false,
|
||||||
|
data: [],
|
||||||
|
};
|
||||||
|
|
||||||
|
export default function serversReducer(
|
||||||
|
state = initialState,
|
||||||
|
action: ServersActionTypes
|
||||||
|
): ServersState {
|
||||||
|
switch (action.type) {
|
||||||
|
case LIST_SERVERS_BEGIN:
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
loading: true,
|
||||||
|
};
|
||||||
|
|
||||||
|
case LIST_SERVERS_SUCCESS:
|
||||||
|
return {
|
||||||
|
loading: false,
|
||||||
|
data: action.payload.servers,
|
||||||
|
};
|
||||||
|
|
||||||
|
case LIST_SERVERS_ERROR:
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
loading: false,
|
||||||
|
};
|
||||||
|
|
||||||
|
default:
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
}
|
@ -2,6 +2,7 @@ import { combineReducers, configureStore } from "@reduxjs/toolkit";
|
|||||||
import settingsReducer from "./reducers/settingsReducer";
|
import settingsReducer from "./reducers/settingsReducer";
|
||||||
import queuesReducer from "./reducers/queuesReducer";
|
import queuesReducer from "./reducers/queuesReducer";
|
||||||
import tasksReducer from "./reducers/tasksReducer";
|
import tasksReducer from "./reducers/tasksReducer";
|
||||||
|
import serversReducer from "./reducers/serversReducer";
|
||||||
import schedulerEntriesReducer from "./reducers/schedulerEntriesReducer";
|
import schedulerEntriesReducer from "./reducers/schedulerEntriesReducer";
|
||||||
import snackbarReducer from "./reducers/snackbarReducer";
|
import snackbarReducer from "./reducers/snackbarReducer";
|
||||||
import queueStatsReducer from "./reducers/queueStatsReducer";
|
import queueStatsReducer from "./reducers/queueStatsReducer";
|
||||||
@ -10,6 +11,7 @@ const rootReducer = combineReducers({
|
|||||||
settings: settingsReducer,
|
settings: settingsReducer,
|
||||||
queues: queuesReducer,
|
queues: queuesReducer,
|
||||||
tasks: tasksReducer,
|
tasks: tasksReducer,
|
||||||
|
servers: serversReducer,
|
||||||
schedulerEntries: schedulerEntriesReducer,
|
schedulerEntries: schedulerEntriesReducer,
|
||||||
snackbar: snackbarReducer,
|
snackbar: snackbarReducer,
|
||||||
queueStats: queueStatsReducer,
|
queueStats: queueStatsReducer,
|
||||||
|
@ -1,10 +1,14 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
|
import { connect, ConnectedProps } from "react-redux";
|
||||||
import Container from "@material-ui/core/Container";
|
import Container from "@material-ui/core/Container";
|
||||||
import { makeStyles } from "@material-ui/core/styles";
|
import { makeStyles } from "@material-ui/core/styles";
|
||||||
import Grid from "@material-ui/core/Grid";
|
import Grid from "@material-ui/core/Grid";
|
||||||
import Paper from "@material-ui/core/Paper";
|
import Paper from "@material-ui/core/Paper";
|
||||||
import Typography from "@material-ui/core/Typography";
|
import Typography from "@material-ui/core/Typography";
|
||||||
import ServersTable from "../components/ServersTable";
|
import ServersTable from "../components/ServersTable";
|
||||||
|
import { listServersAsync } from "../actions/serversActions";
|
||||||
|
import { AppState } from "../store";
|
||||||
|
import { usePolling } from "../hooks";
|
||||||
|
|
||||||
const useStyles = makeStyles((theme) => ({
|
const useStyles = makeStyles((theme) => ({
|
||||||
container: {
|
container: {
|
||||||
@ -23,8 +27,24 @@ const useStyles = makeStyles((theme) => ({
|
|||||||
},
|
},
|
||||||
}));
|
}));
|
||||||
|
|
||||||
export default function ServersView() {
|
function mapStateToProps(state: AppState) {
|
||||||
|
return {
|
||||||
|
loading: state.servers.loading,
|
||||||
|
servers: state.servers.data,
|
||||||
|
pollInterval: state.settings.pollInterval,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const connector = connect(mapStateToProps, { listServersAsync });
|
||||||
|
|
||||||
|
type Props = ConnectedProps<typeof connector>;
|
||||||
|
|
||||||
|
function ServersView(props: Props) {
|
||||||
|
const { pollInterval, listServersAsync } = props;
|
||||||
const classes = useStyles();
|
const classes = useStyles();
|
||||||
|
|
||||||
|
usePolling(listServersAsync, pollInterval);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Container maxWidth="lg" className={classes.container}>
|
<Container maxWidth="lg" className={classes.container}>
|
||||||
<Grid container spacing={3}>
|
<Grid container spacing={3}>
|
||||||
@ -33,10 +53,12 @@ export default function ServersView() {
|
|||||||
<Typography variant="h6" className={classes.heading}>
|
<Typography variant="h6" className={classes.heading}>
|
||||||
Servers
|
Servers
|
||||||
</Typography>
|
</Typography>
|
||||||
<ServersTable servers={[]} />
|
<ServersTable servers={props.servers} />
|
||||||
</Paper>
|
</Paper>
|
||||||
</Grid>
|
</Grid>
|
||||||
</Grid>
|
</Grid>
|
||||||
</Container>
|
</Container>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export default connector(ServersView);
|
||||||
|
Loading…
Reference in New Issue
Block a user