mirror of
https://github.com/hibiken/asynqmon.git
synced 2025-10-04 03:01:59 +08:00
(ui): Add Completed section in QueueSizeChart
This commit is contained in:
@@ -348,6 +348,9 @@ func toArchivedTasks(in []*asynq.TaskInfo, pf PayloadFormatter) []*archivedTask
|
|||||||
type completedTask struct {
|
type completedTask struct {
|
||||||
*baseTask
|
*baseTask
|
||||||
CompletedAt time.Time `json:"completed_at"`
|
CompletedAt time.Time `json:"completed_at"`
|
||||||
|
Result string `json:"result"`
|
||||||
|
// Number of seconds left for retention (i.e. (CompletedAt + ResultTTL) - Now)
|
||||||
|
ResultTTL int64 `json:"result_ttl_seconds"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func toCompletedTask(ti *asynq.TaskInfo, pf PayloadFormatter) *completedTask {
|
func toCompletedTask(ti *asynq.TaskInfo, pf PayloadFormatter) *completedTask {
|
||||||
@@ -360,9 +363,13 @@ func toCompletedTask(ti *asynq.TaskInfo, pf PayloadFormatter) *completedTask {
|
|||||||
Retried: ti.Retried,
|
Retried: ti.Retried,
|
||||||
LastError: ti.LastErr,
|
LastError: ti.LastErr,
|
||||||
}
|
}
|
||||||
|
ttl := ti.CompletedAt.Add(ti.ResultTTL).Sub(time.Now())
|
||||||
return &completedTask{
|
return &completedTask{
|
||||||
baseTask: base,
|
baseTask: base,
|
||||||
CompletedAt: ti.CompletedAt,
|
CompletedAt: ti.CompletedAt,
|
||||||
|
ResultTTL: int64(ttl.Seconds()),
|
||||||
|
// TODO: Use resultFormatter instead
|
||||||
|
Result: defaultPayloadFormatter.FormatPayload("", ti.Result),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -329,6 +329,8 @@ export interface CompletedTask extends BaseTask {
|
|||||||
max_retry: number;
|
max_retry: number;
|
||||||
retried: number;
|
retried: number;
|
||||||
completed_at: string;
|
completed_at: string;
|
||||||
|
result: string;
|
||||||
|
result_ttl_seconds: number
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ServerInfo {
|
export interface ServerInfo {
|
||||||
|
@@ -26,7 +26,12 @@ import TablePaginationActions, {
|
|||||||
} from "./TablePaginationActions";
|
} from "./TablePaginationActions";
|
||||||
import { taskRowsPerPageChange } from "../actions/settingsActions";
|
import { taskRowsPerPageChange } from "../actions/settingsActions";
|
||||||
import TableActions from "./TableActions";
|
import TableActions from "./TableActions";
|
||||||
import { timeAgo, uuidPrefix } from "../utils";
|
import {
|
||||||
|
durationFromSeconds,
|
||||||
|
stringifyDuration,
|
||||||
|
timeAgo,
|
||||||
|
uuidPrefix,
|
||||||
|
} from "../utils";
|
||||||
import { usePolling } from "../hooks";
|
import { usePolling } from "../hooks";
|
||||||
import { CompletedTaskExtended } from "../reducers/tasksReducer";
|
import { CompletedTaskExtended } from "../reducers/tasksReducer";
|
||||||
import { TableColumn } from "../types/table";
|
import { TableColumn } from "../types/table";
|
||||||
@@ -132,8 +137,9 @@ function CompletedTasksTable(props: Props & ReduxProps) {
|
|||||||
{ key: "id", label: "ID", align: "left" },
|
{ key: "id", label: "ID", align: "left" },
|
||||||
{ key: "type", label: "Type", align: "left" },
|
{ key: "type", label: "Type", align: "left" },
|
||||||
{ key: "payload", label: "Payload", align: "left" },
|
{ key: "payload", label: "Payload", align: "left" },
|
||||||
{ key: "completed_at", label: "Completed Time", align: "left" },
|
{ key: "completed_at", label: "Completed", align: "left" },
|
||||||
{ key: "result", label: "Result", align: "left" },
|
{ key: "result", label: "Result", align: "left" },
|
||||||
|
{ key: "ttl", label: "TTL", align: "left" },
|
||||||
{ key: "actions", label: "Actions", align: "center" },
|
{ key: "actions", label: "Actions", align: "center" },
|
||||||
];
|
];
|
||||||
|
|
||||||
@@ -310,7 +316,21 @@ function Row(props: RowProps) {
|
|||||||
</SyntaxHighlighter>
|
</SyntaxHighlighter>
|
||||||
</TableCell>
|
</TableCell>
|
||||||
<TableCell>{timeAgo(task.completed_at)}</TableCell>
|
<TableCell>{timeAgo(task.completed_at)}</TableCell>
|
||||||
<TableCell>{"TODO: Result data here"}</TableCell>
|
<TableCell>
|
||||||
|
<SyntaxHighlighter
|
||||||
|
language="json"
|
||||||
|
customStyle={{ margin: 0, maxWidth: 400 }}
|
||||||
|
>
|
||||||
|
{task.result}
|
||||||
|
</SyntaxHighlighter>
|
||||||
|
</TableCell>
|
||||||
|
<TableCell>
|
||||||
|
{task.result_ttl_seconds > 0
|
||||||
|
? `${stringifyDuration(
|
||||||
|
durationFromSeconds(task.result_ttl_seconds)
|
||||||
|
)} left`
|
||||||
|
: `expired`}
|
||||||
|
</TableCell>
|
||||||
<TableCell
|
<TableCell
|
||||||
align="center"
|
align="center"
|
||||||
className={classes.actionCell}
|
className={classes.actionCell}
|
||||||
|
@@ -23,6 +23,7 @@ interface TaskBreakdown {
|
|||||||
scheduled: number; // number of scheduled tasks in the queue.
|
scheduled: number; // number of scheduled tasks in the queue.
|
||||||
retry: number; // number of retry tasks in the queue.
|
retry: number; // number of retry tasks in the queue.
|
||||||
archived: number; // number of archived tasks in the queue.
|
archived: number; // number of archived tasks in the queue.
|
||||||
|
completed: number; // number of completed tasks in the queue.
|
||||||
}
|
}
|
||||||
|
|
||||||
function QueueSizeChart(props: Props) {
|
function QueueSizeChart(props: Props) {
|
||||||
@@ -55,6 +56,7 @@ function QueueSizeChart(props: Props) {
|
|||||||
<Bar dataKey="scheduled" stackId="a" fill="#fdd663" />
|
<Bar dataKey="scheduled" stackId="a" fill="#fdd663" />
|
||||||
<Bar dataKey="retry" stackId="a" fill="#f666a9" />
|
<Bar dataKey="retry" stackId="a" fill="#f666a9" />
|
||||||
<Bar dataKey="archived" stackId="a" fill="#ac4776" />
|
<Bar dataKey="archived" stackId="a" fill="#ac4776" />
|
||||||
|
<Bar dataKey="completed" stackId="a" fill="#4bb543" />
|
||||||
</BarChart>
|
</BarChart>
|
||||||
</ResponsiveContainer>
|
</ResponsiveContainer>
|
||||||
);
|
);
|
||||||
|
@@ -25,17 +25,22 @@ interface Duration {
|
|||||||
totalSeconds: number;
|
totalSeconds: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
// start and end are in milliseconds.
|
// Returns a duration from the number of seconds provided.
|
||||||
function durationBetween(start: number, end: number): Duration {
|
export function durationFromSeconds(totalSeconds: number): Duration {
|
||||||
const durationInMillisec = start - end;
|
|
||||||
const totalSeconds = Math.floor(durationInMillisec / 1000);
|
|
||||||
const hour = Math.floor(totalSeconds / 3600);
|
const hour = Math.floor(totalSeconds / 3600);
|
||||||
const minute = Math.floor((totalSeconds - 3600 * hour) / 60);
|
const minute = Math.floor((totalSeconds - 3600 * hour) / 60);
|
||||||
const second = totalSeconds - 3600 * hour - 60 * minute;
|
const second = totalSeconds - 3600 * hour - 60 * minute;
|
||||||
return { hour, minute, second, totalSeconds };
|
return { hour, minute, second, totalSeconds };
|
||||||
}
|
}
|
||||||
|
|
||||||
function stringifyDuration(d: Duration): string {
|
// start and end are in milliseconds.
|
||||||
|
function durationBetween(start: number, end: number): Duration {
|
||||||
|
const durationInMillisec = start - end;
|
||||||
|
const totalSeconds = Math.floor(durationInMillisec / 1000);
|
||||||
|
return durationFromSeconds(totalSeconds);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function stringifyDuration(d: Duration): string {
|
||||||
if (d.hour > 24) {
|
if (d.hour > 24) {
|
||||||
const n = Math.floor(d.hour / 24);
|
const n = Math.floor(d.hour / 24);
|
||||||
return n + (n === 1 ? " day" : " days");
|
return n + (n === 1 ? " day" : " days");
|
||||||
|
Reference in New Issue
Block a user