mirror of
https://github.com/hibiken/asynqmon.git
synced 2025-01-19 11:15:53 +08:00
Add delete task button to RetryTasksTable
This commit is contained in:
parent
48c2cda3bf
commit
601a7c8add
@ -125,6 +125,7 @@ func toPendingTasks(in []*asynq.PendingTask) []*PendingTask {
|
|||||||
|
|
||||||
type ScheduledTask struct {
|
type ScheduledTask struct {
|
||||||
*BaseTask
|
*BaseTask
|
||||||
|
Key string `json:"key"`
|
||||||
NextProcessAt time.Time `json:"next_process_at"`
|
NextProcessAt time.Time `json:"next_process_at"`
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -137,6 +138,7 @@ func toScheduledTask(t *asynq.ScheduledTask) *ScheduledTask {
|
|||||||
}
|
}
|
||||||
return &ScheduledTask{
|
return &ScheduledTask{
|
||||||
BaseTask: base,
|
BaseTask: base,
|
||||||
|
Key: t.Key(),
|
||||||
NextProcessAt: t.NextProcessAt,
|
NextProcessAt: t.NextProcessAt,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -151,6 +153,7 @@ func toScheduledTasks(in []*asynq.ScheduledTask) []*ScheduledTask {
|
|||||||
|
|
||||||
type RetryTask struct {
|
type RetryTask struct {
|
||||||
*BaseTask
|
*BaseTask
|
||||||
|
Key string `json:"key"`
|
||||||
NextProcessAt time.Time `json:"next_process_at"`
|
NextProcessAt time.Time `json:"next_process_at"`
|
||||||
MaxRetry int `json:"max_retry"`
|
MaxRetry int `json:"max_retry"`
|
||||||
Retried int `json:"retried"`
|
Retried int `json:"retried"`
|
||||||
@ -166,6 +169,7 @@ func toRetryTask(t *asynq.RetryTask) *RetryTask {
|
|||||||
}
|
}
|
||||||
return &RetryTask{
|
return &RetryTask{
|
||||||
BaseTask: base,
|
BaseTask: base,
|
||||||
|
Key: t.Key(),
|
||||||
NextProcessAt: t.NextProcessAt,
|
NextProcessAt: t.NextProcessAt,
|
||||||
MaxRetry: t.MaxRetry,
|
MaxRetry: t.MaxRetry,
|
||||||
Retried: t.Retried,
|
Retried: t.Retried,
|
||||||
@ -183,6 +187,7 @@ func toRetryTasks(in []*asynq.RetryTask) []*RetryTask {
|
|||||||
|
|
||||||
type DeadTask struct {
|
type DeadTask struct {
|
||||||
*BaseTask
|
*BaseTask
|
||||||
|
Key string `json:"key"`
|
||||||
MaxRetry int `json:"max_retry"`
|
MaxRetry int `json:"max_retry"`
|
||||||
Retried int `json:"retried"`
|
Retried int `json:"retried"`
|
||||||
ErrorMsg string `json:"error_message"`
|
ErrorMsg string `json:"error_message"`
|
||||||
@ -198,6 +203,7 @@ func toDeadTask(t *asynq.DeadTask) *DeadTask {
|
|||||||
}
|
}
|
||||||
return &DeadTask{
|
return &DeadTask{
|
||||||
BaseTask: base,
|
BaseTask: base,
|
||||||
|
Key: t.Key(),
|
||||||
MaxRetry: t.MaxRetry,
|
MaxRetry: t.MaxRetry,
|
||||||
Retried: t.Retried,
|
Retried: t.Retried,
|
||||||
ErrorMsg: t.ErrorMsg,
|
ErrorMsg: t.ErrorMsg,
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import {
|
import {
|
||||||
cancelActiveTask,
|
cancelActiveTask,
|
||||||
|
deleteRetryTask,
|
||||||
listActiveTasks,
|
listActiveTasks,
|
||||||
ListActiveTasksResponse,
|
ListActiveTasksResponse,
|
||||||
listDeadTasks,
|
listDeadTasks,
|
||||||
@ -33,6 +34,9 @@ export const LIST_DEAD_TASKS_ERROR = "LIST_DEAD_TASKS_ERROR";
|
|||||||
export const CANCEL_ACTIVE_TASK_BEGIN = "CANCEL_ACTIVE_TASK_BEGIN";
|
export const CANCEL_ACTIVE_TASK_BEGIN = "CANCEL_ACTIVE_TASK_BEGIN";
|
||||||
export const CANCEL_ACTIVE_TASK_SUCCESS = "CANCEL_ACTIVE_TASK_SUCCESS";
|
export const CANCEL_ACTIVE_TASK_SUCCESS = "CANCEL_ACTIVE_TASK_SUCCESS";
|
||||||
export const CANCEL_ACTIVE_TASK_ERROR = "CANCEL_ACTIVE_TASK_ERROR";
|
export const CANCEL_ACTIVE_TASK_ERROR = "CANCEL_ACTIVE_TASK_ERROR";
|
||||||
|
export const DELETE_RETRY_TASK_BEGIN = "DELETE_RETRY_TASK_BEGIN";
|
||||||
|
export const DELETE_RETRY_TASK_SUCCESS = "DELETE_RETRY_TASK_SUCCESS";
|
||||||
|
export const DELETE_RETRY_TASK_ERROR = "DELETE_RETRY_TASK_ERROR";
|
||||||
|
|
||||||
interface ListActiveTasksBeginAction {
|
interface ListActiveTasksBeginAction {
|
||||||
type: typeof LIST_ACTIVE_TASKS_BEGIN;
|
type: typeof LIST_ACTIVE_TASKS_BEGIN;
|
||||||
@ -138,6 +142,24 @@ interface CancelActiveTaskErrorAction {
|
|||||||
error: string;
|
error: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface DeleteRetryTaskBeginAction {
|
||||||
|
type: typeof DELETE_RETRY_TASK_BEGIN;
|
||||||
|
queue: string;
|
||||||
|
taskKey: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface DeleteRetryTaskSuccessAction {
|
||||||
|
type: typeof DELETE_RETRY_TASK_SUCCESS;
|
||||||
|
queue: string;
|
||||||
|
taskKey: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface DeleteRetryTaskErrorAction {
|
||||||
|
type: typeof DELETE_RETRY_TASK_ERROR;
|
||||||
|
queue: string;
|
||||||
|
taskKey: string;
|
||||||
|
error: string;
|
||||||
|
}
|
||||||
// Union of all tasks related action types.
|
// Union of all tasks related action types.
|
||||||
export type TasksActionTypes =
|
export type TasksActionTypes =
|
||||||
| ListActiveTasksBeginAction
|
| ListActiveTasksBeginAction
|
||||||
@ -157,7 +179,10 @@ export type TasksActionTypes =
|
|||||||
| ListDeadTasksErrorAction
|
| ListDeadTasksErrorAction
|
||||||
| CancelActiveTaskBeginAction
|
| CancelActiveTaskBeginAction
|
||||||
| CancelActiveTaskSuccessAction
|
| CancelActiveTaskSuccessAction
|
||||||
| CancelActiveTaskErrorAction;
|
| CancelActiveTaskErrorAction
|
||||||
|
| DeleteRetryTaskBeginAction
|
||||||
|
| DeleteRetryTaskSuccessAction
|
||||||
|
| DeleteRetryTaskErrorAction;
|
||||||
|
|
||||||
export function listActiveTasksAsync(
|
export function listActiveTasksAsync(
|
||||||
qname: string,
|
qname: string,
|
||||||
@ -290,3 +315,21 @@ export function cancelActiveTaskAsync(queue: string, taskId: string) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function deleteRetryTaskAsync(queue: string, taskKey: string) {
|
||||||
|
return async (dispatch: Dispatch<TasksActionTypes>) => {
|
||||||
|
dispatch({ type: DELETE_RETRY_TASK_BEGIN, queue, taskKey });
|
||||||
|
try {
|
||||||
|
await deleteRetryTask(queue, taskKey);
|
||||||
|
dispatch({ type: DELETE_RETRY_TASK_SUCCESS, queue, taskKey });
|
||||||
|
} catch (error) {
|
||||||
|
console.error("deleteRetryTaskAsync: ", error);
|
||||||
|
dispatch({
|
||||||
|
type: DELETE_RETRY_TASK_ERROR,
|
||||||
|
error: `Could not delete task: ${taskKey}`,
|
||||||
|
queue,
|
||||||
|
taskKey,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
@ -79,12 +79,14 @@ export interface PendingTask extends BaseTask {
|
|||||||
|
|
||||||
export interface ScheduledTask extends BaseTask {
|
export interface ScheduledTask extends BaseTask {
|
||||||
id: string;
|
id: string;
|
||||||
|
key: string;
|
||||||
queue: string;
|
queue: string;
|
||||||
next_process_at: string;
|
next_process_at: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface RetryTask extends BaseTask {
|
export interface RetryTask extends BaseTask {
|
||||||
id: string;
|
id: string;
|
||||||
|
key: string;
|
||||||
queue: string;
|
queue: string;
|
||||||
next_process_at: string;
|
next_process_at: string;
|
||||||
max_retry: number;
|
max_retry: number;
|
||||||
@ -94,6 +96,7 @@ export interface RetryTask extends BaseTask {
|
|||||||
|
|
||||||
export interface DeadTask extends BaseTask {
|
export interface DeadTask extends BaseTask {
|
||||||
id: string;
|
id: string;
|
||||||
|
key: string;
|
||||||
queue: string;
|
queue: string;
|
||||||
max_retry: number;
|
max_retry: number;
|
||||||
retried: number;
|
retried: number;
|
||||||
@ -240,6 +243,16 @@ export async function listDeadTasks(
|
|||||||
return resp.data;
|
return resp.data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function deleteRetryTask(
|
||||||
|
qname: string,
|
||||||
|
taskKey: string
|
||||||
|
): Promise<void> {
|
||||||
|
await axios({
|
||||||
|
method: "delete",
|
||||||
|
url: `${BASE_URL}/queues/${qname}/retry_tasks/${taskKey}`,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
export async function listSchedulerEntries(): Promise<ListSchedulerEntriesResponse> {
|
export async function listSchedulerEntries(): Promise<ListSchedulerEntriesResponse> {
|
||||||
const resp = await axios({
|
const resp = await axios({
|
||||||
method: "get",
|
method: "get",
|
||||||
|
@ -21,15 +21,18 @@ import Alert from "@material-ui/lab/Alert";
|
|||||||
import AlertTitle from "@material-ui/lab/AlertTitle";
|
import AlertTitle from "@material-ui/lab/AlertTitle";
|
||||||
import SyntaxHighlighter from "react-syntax-highlighter";
|
import SyntaxHighlighter from "react-syntax-highlighter";
|
||||||
import syntaxHighlightStyle from "react-syntax-highlighter/dist/esm/styles/hljs/github";
|
import syntaxHighlightStyle from "react-syntax-highlighter/dist/esm/styles/hljs/github";
|
||||||
import { listRetryTasksAsync } from "../actions/tasksActions";
|
import {
|
||||||
|
listRetryTasksAsync,
|
||||||
|
deleteRetryTaskAsync,
|
||||||
|
} from "../actions/tasksActions";
|
||||||
import { AppState } from "../store";
|
import { AppState } from "../store";
|
||||||
import { RetryTask } from "../api";
|
|
||||||
import TablePaginationActions, {
|
import TablePaginationActions, {
|
||||||
defaultPageSize,
|
defaultPageSize,
|
||||||
rowsPerPageOptions,
|
rowsPerPageOptions,
|
||||||
} from "./TablePaginationActions";
|
} from "./TablePaginationActions";
|
||||||
import { durationBefore } from "../timeutil";
|
import { durationBefore } from "../timeutil";
|
||||||
import { usePolling } from "../hooks";
|
import { usePolling } from "../hooks";
|
||||||
|
import { RetryTaskExtended } from "../reducers/tasksReducer";
|
||||||
|
|
||||||
const useStyles = makeStyles({
|
const useStyles = makeStyles({
|
||||||
table: {
|
table: {
|
||||||
@ -45,7 +48,7 @@ function mapStateToProps(state: AppState) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
const mapDispatchToProps = { listRetryTasksAsync };
|
const mapDispatchToProps = { listRetryTasksAsync, deleteRetryTaskAsync };
|
||||||
|
|
||||||
const connector = connect(mapStateToProps, mapDispatchToProps);
|
const connector = connect(mapStateToProps, mapDispatchToProps);
|
||||||
|
|
||||||
@ -120,7 +123,13 @@ function RetryTasksTable(props: Props & ReduxProps) {
|
|||||||
</TableHead>
|
</TableHead>
|
||||||
<TableBody>
|
<TableBody>
|
||||||
{props.tasks.map((task) => (
|
{props.tasks.map((task) => (
|
||||||
<Row key={task.id} task={task} />
|
<Row
|
||||||
|
key={task.id}
|
||||||
|
task={task}
|
||||||
|
onDeleteClick={() => {
|
||||||
|
props.deleteRetryTaskAsync(task.queue, task.key);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
))}
|
))}
|
||||||
</TableBody>
|
</TableBody>
|
||||||
<TableFooter>
|
<TableFooter>
|
||||||
@ -154,7 +163,7 @@ const useRowStyles = makeStyles({
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
function Row(props: { task: RetryTask }) {
|
function Row(props: { task: RetryTaskExtended; onDeleteClick: () => void }) {
|
||||||
const { task } = props;
|
const { task } = props;
|
||||||
const [open, setOpen] = React.useState(false);
|
const [open, setOpen] = React.useState(false);
|
||||||
const classes = useRowStyles();
|
const classes = useRowStyles();
|
||||||
@ -179,7 +188,9 @@ function Row(props: { task: RetryTask }) {
|
|||||||
<TableCell>{task.retried}</TableCell>
|
<TableCell>{task.retried}</TableCell>
|
||||||
<TableCell>{task.max_retry}</TableCell>
|
<TableCell>{task.max_retry}</TableCell>
|
||||||
<TableCell>
|
<TableCell>
|
||||||
<Button>Cancel</Button>
|
<Button disabled={task.requestPending} onClick={props.onDeleteClick}>
|
||||||
|
Delete
|
||||||
|
</Button>
|
||||||
</TableCell>
|
</TableCell>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
<TableRow>
|
<TableRow>
|
||||||
|
@ -14,6 +14,7 @@ import {
|
|||||||
DELETE_QUEUE_SUCCESS,
|
DELETE_QUEUE_SUCCESS,
|
||||||
} from "../actions/queuesActions";
|
} from "../actions/queuesActions";
|
||||||
import {
|
import {
|
||||||
|
DELETE_RETRY_TASK_SUCCESS,
|
||||||
LIST_ACTIVE_TASKS_SUCCESS,
|
LIST_ACTIVE_TASKS_SUCCESS,
|
||||||
LIST_DEAD_TASKS_SUCCESS,
|
LIST_DEAD_TASKS_SUCCESS,
|
||||||
LIST_PENDING_TASKS_SUCCESS,
|
LIST_PENDING_TASKS_SUCCESS,
|
||||||
@ -147,6 +148,22 @@ function queuesReducer(
|
|||||||
return { ...state, data: newData };
|
return { ...state, data: newData };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case DELETE_RETRY_TASK_SUCCESS: {
|
||||||
|
const newData = state.data.map((queueInfo) => {
|
||||||
|
if (queueInfo.name !== action.queue) {
|
||||||
|
return queueInfo;
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
...queueInfo,
|
||||||
|
currentStats: {
|
||||||
|
...queueInfo.currentStats,
|
||||||
|
retry: queueInfo.currentStats.retry - 1,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
});
|
||||||
|
return { ...state, data: newData };
|
||||||
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
|
@ -18,6 +18,9 @@ import {
|
|||||||
CANCEL_ACTIVE_TASK_BEGIN,
|
CANCEL_ACTIVE_TASK_BEGIN,
|
||||||
CANCEL_ACTIVE_TASK_SUCCESS,
|
CANCEL_ACTIVE_TASK_SUCCESS,
|
||||||
CANCEL_ACTIVE_TASK_ERROR,
|
CANCEL_ACTIVE_TASK_ERROR,
|
||||||
|
DELETE_RETRY_TASK_BEGIN,
|
||||||
|
DELETE_RETRY_TASK_SUCCESS,
|
||||||
|
DELETE_RETRY_TASK_ERROR,
|
||||||
} from "../actions/tasksActions";
|
} from "../actions/tasksActions";
|
||||||
import {
|
import {
|
||||||
ActiveTask,
|
ActiveTask,
|
||||||
@ -37,6 +40,12 @@ export interface ActiveTaskExtended extends ActiveTask {
|
|||||||
canceling: boolean;
|
canceling: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface RetryTaskExtended extends RetryTask {
|
||||||
|
// Indicates that a request has been sent for this
|
||||||
|
// task and awaiting for a response.
|
||||||
|
requestPending: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
interface TasksState {
|
interface TasksState {
|
||||||
activeTasks: {
|
activeTasks: {
|
||||||
loading: boolean;
|
loading: boolean;
|
||||||
@ -56,7 +65,7 @@ interface TasksState {
|
|||||||
retryTasks: {
|
retryTasks: {
|
||||||
loading: boolean;
|
loading: boolean;
|
||||||
error: string;
|
error: string;
|
||||||
data: RetryTask[];
|
data: RetryTaskExtended[];
|
||||||
};
|
};
|
||||||
deadTasks: {
|
deadTasks: {
|
||||||
loading: boolean;
|
loading: boolean;
|
||||||
@ -208,7 +217,10 @@ function tasksReducer(
|
|||||||
retryTasks: {
|
retryTasks: {
|
||||||
loading: false,
|
loading: false,
|
||||||
error: "",
|
error: "",
|
||||||
data: action.payload.tasks,
|
data: action.payload.tasks.map((task) => ({
|
||||||
|
...task,
|
||||||
|
requestPending: false,
|
||||||
|
})),
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -299,6 +311,45 @@ function tasksReducer(
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
case DELETE_RETRY_TASK_BEGIN:
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
retryTasks: {
|
||||||
|
...state.retryTasks,
|
||||||
|
data: state.retryTasks.data.map((task) => {
|
||||||
|
if (task.key !== action.taskKey) {
|
||||||
|
return task;
|
||||||
|
}
|
||||||
|
return { ...task, requestPending: true };
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
case DELETE_RETRY_TASK_SUCCESS:
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
retryTasks: {
|
||||||
|
...state.retryTasks,
|
||||||
|
data: state.retryTasks.data.filter(
|
||||||
|
(task) => task.key !== action.taskKey
|
||||||
|
),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
case DELETE_RETRY_TASK_ERROR:
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
retryTasks: {
|
||||||
|
...state.retryTasks,
|
||||||
|
data: state.retryTasks.data.map((task) => {
|
||||||
|
if (task.key !== action.taskKey) {
|
||||||
|
return task;
|
||||||
|
}
|
||||||
|
return { ...task, requestPending: false };
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user