mirror of
https://github.com/hibiken/asynqmon.git
synced 2025-10-04 03:01:59 +08:00
Update task details view
This commit is contained in:
@@ -154,6 +154,22 @@ type taskInfo struct {
|
|||||||
// NextProcessAt is the time the task is scheduled to be processed in RFC3339 format.
|
// NextProcessAt is the time the task is scheduled to be processed in RFC3339 format.
|
||||||
// If not applicable, empty string.
|
// If not applicable, empty string.
|
||||||
NextProcessAt string `json:"next_process_at"`
|
NextProcessAt string `json:"next_process_at"`
|
||||||
|
// CompletedAt is the time the task was successfully processed in RFC3339 format.
|
||||||
|
// If not applicable, empty string.
|
||||||
|
CompletedAt string `json:"completed_at"`
|
||||||
|
// Result is the result data associated with the task.
|
||||||
|
Result string `json:"result"`
|
||||||
|
// TTL is the number of seconds the task has left to be retained in the queue.
|
||||||
|
// This is calculated by (CompletedAt + ResultTTL) - Now.
|
||||||
|
TTL int64 `json:"ttl_seconds"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// taskTTL calculates TTL for the given task.
|
||||||
|
func taskTTL(task *asynq.TaskInfo) time.Duration {
|
||||||
|
if task.State != asynq.TaskStateCompleted {
|
||||||
|
return 0 // N/A
|
||||||
|
}
|
||||||
|
return task.CompletedAt.Add(task.ResultTTL).Sub(time.Now())
|
||||||
}
|
}
|
||||||
|
|
||||||
// formatTimeInRFC3339 formats t in RFC3339 if the value is non-zero.
|
// formatTimeInRFC3339 formats t in RFC3339 if the value is non-zero.
|
||||||
@@ -179,6 +195,10 @@ func toTaskInfo(info *asynq.TaskInfo, pf PayloadFormatter) *taskInfo {
|
|||||||
Timeout: int(info.Timeout.Seconds()),
|
Timeout: int(info.Timeout.Seconds()),
|
||||||
Deadline: formatTimeInRFC3339(info.Deadline),
|
Deadline: formatTimeInRFC3339(info.Deadline),
|
||||||
NextProcessAt: formatTimeInRFC3339(info.NextProcessAt),
|
NextProcessAt: formatTimeInRFC3339(info.NextProcessAt),
|
||||||
|
CompletedAt: formatTimeInRFC3339(info.CompletedAt),
|
||||||
|
// TODO: Replace this with resultFormatter
|
||||||
|
Result: defaultPayloadFormatter.FormatPayload("", info.Result),
|
||||||
|
TTL: int64(taskTTL(info).Seconds()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -350,7 +370,7 @@ type completedTask struct {
|
|||||||
CompletedAt time.Time `json:"completed_at"`
|
CompletedAt time.Time `json:"completed_at"`
|
||||||
Result string `json:"result"`
|
Result string `json:"result"`
|
||||||
// Number of seconds left for retention (i.e. (CompletedAt + ResultTTL) - Now)
|
// Number of seconds left for retention (i.e. (CompletedAt + ResultTTL) - Now)
|
||||||
ResultTTL int64 `json:"result_ttl_seconds"`
|
TTL int64 `json:"ttl_seconds"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func toCompletedTask(ti *asynq.TaskInfo, pf PayloadFormatter) *completedTask {
|
func toCompletedTask(ti *asynq.TaskInfo, pf PayloadFormatter) *completedTask {
|
||||||
@@ -363,11 +383,10 @@ 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()),
|
TTL: int64(taskTTL(ti).Seconds()),
|
||||||
// TODO: Use resultFormatter instead
|
// TODO: Use resultFormatter instead
|
||||||
Result: defaultPayloadFormatter.FormatPayload("", ti.Result),
|
Result: defaultPayloadFormatter.FormatPayload("", ti.Result),
|
||||||
}
|
}
|
||||||
|
@@ -276,6 +276,9 @@ export interface TaskInfo {
|
|||||||
next_process_at: string;
|
next_process_at: string;
|
||||||
timeout_seconds: number;
|
timeout_seconds: number;
|
||||||
deadline: string;
|
deadline: string;
|
||||||
|
completed_at: string;
|
||||||
|
result: string;
|
||||||
|
ttl_seconds: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ActiveTask extends BaseTask {
|
export interface ActiveTask extends BaseTask {
|
||||||
@@ -330,7 +333,7 @@ export interface CompletedTask extends BaseTask {
|
|||||||
retried: number;
|
retried: number;
|
||||||
completed_at: string;
|
completed_at: string;
|
||||||
result: string;
|
result: string;
|
||||||
result_ttl_seconds: number
|
ttl_seconds: number
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ServerInfo {
|
export interface ServerInfo {
|
||||||
|
@@ -325,10 +325,8 @@ function Row(props: RowProps) {
|
|||||||
</SyntaxHighlighter>
|
</SyntaxHighlighter>
|
||||||
</TableCell>
|
</TableCell>
|
||||||
<TableCell>
|
<TableCell>
|
||||||
{task.result_ttl_seconds > 0
|
{task.ttl_seconds > 0
|
||||||
? `${stringifyDuration(
|
? `${stringifyDuration(durationFromSeconds(task.ttl_seconds))} left`
|
||||||
durationFromSeconds(task.result_ttl_seconds)
|
|
||||||
)} left`
|
|
||||||
: `expired`}
|
: `expired`}
|
||||||
</TableCell>
|
</TableCell>
|
||||||
<TableCell
|
<TableCell
|
||||||
|
@@ -18,6 +18,7 @@ import { TaskDetailsRouteParams } from "../paths";
|
|||||||
import { usePolling } from "../hooks";
|
import { usePolling } from "../hooks";
|
||||||
import { listQueuesAsync } from "../actions/queuesActions";
|
import { listQueuesAsync } from "../actions/queuesActions";
|
||||||
import SyntaxHighlighter from "../components/SyntaxHighlighter";
|
import SyntaxHighlighter from "../components/SyntaxHighlighter";
|
||||||
|
import { durationFromSeconds, stringifyDuration } from "../utils";
|
||||||
|
|
||||||
function mapStateToProps(state: AppState) {
|
function mapStateToProps(state: AppState) {
|
||||||
return {
|
return {
|
||||||
@@ -232,6 +233,56 @@ function TaskDetailsView(props: Props) {
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
{
|
||||||
|
/* Completed Task Only */ taskInfo?.state === "completed" && (
|
||||||
|
<>
|
||||||
|
<div className={classes.infoRow}>
|
||||||
|
<Typography
|
||||||
|
variant="subtitle2"
|
||||||
|
className={classes.infoKeyCell}
|
||||||
|
>
|
||||||
|
Completed:{" "}
|
||||||
|
</Typography>
|
||||||
|
<div className={classes.infoValueCell}>
|
||||||
|
<Typography>{taskInfo.completed_at}</Typography>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className={classes.infoRow}>
|
||||||
|
<Typography
|
||||||
|
variant="subtitle2"
|
||||||
|
className={classes.infoKeyCell}
|
||||||
|
>
|
||||||
|
Result:{" "}
|
||||||
|
</Typography>
|
||||||
|
<div className={classes.infoValueCell}>
|
||||||
|
<SyntaxHighlighter
|
||||||
|
language="json"
|
||||||
|
customStyle={{ margin: 0, maxWidth: 400 }}
|
||||||
|
>
|
||||||
|
{taskInfo.result}
|
||||||
|
</SyntaxHighlighter>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className={classes.infoRow}>
|
||||||
|
<Typography
|
||||||
|
variant="subtitle2"
|
||||||
|
className={classes.infoKeyCell}
|
||||||
|
>
|
||||||
|
TTL:{" "}
|
||||||
|
</Typography>
|
||||||
|
<Typography className={classes.infoValueCell}>
|
||||||
|
<Typography>
|
||||||
|
{taskInfo.ttl_seconds > 0
|
||||||
|
? `${stringifyDuration(
|
||||||
|
durationFromSeconds(taskInfo.ttl_seconds)
|
||||||
|
)} left`
|
||||||
|
: "expired"}
|
||||||
|
</Typography>
|
||||||
|
</Typography>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
</Paper>
|
</Paper>
|
||||||
)}
|
)}
|
||||||
<div className={classes.footer}>
|
<div className={classes.footer}>
|
||||||
|
Reference in New Issue
Block a user