Skip to content

Commit a1321aa

Browse files
committed
console: better reporting of syncs errors
1 parent 6c186bd commit a1321aa

File tree

4 files changed

+53
-26
lines changed

4 files changed

+53
-26
lines changed

webapps/console/pages/[workspaceId]/syncs/tasks.tsx

Lines changed: 38 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ import hash from "object-hash";
3636
import { useConfigObjectLinks, useConfigObjectList } from "../../../lib/store";
3737
import { Spinner } from "../../../components/GlobalLoader/GlobalLoader";
3838
import { MdOutlineCancel } from "react-icons/md";
39+
import escape from "lodash/escape";
3940

4041
dayjs.extend(utc);
4142
dayjs.extend(relativeTime);
@@ -105,7 +106,9 @@ function TaskStatus0({ task, loading }: { task: TasksDbModel & TaskStats; loadin
105106
}
106107

107108
const SyncStatus: React.FC<
108-
PropsWithChildren<{ status: "PARTIAL" | "CANCELLED" | "FAILED" | "SUCCESS" | "RUNNING" | "SKIPPED" }>
109+
PropsWithChildren<{
110+
status: "PARTIAL" | "CANCELLED" | "TIME_EXCEEDED" | "FAILED" | "SUCCESS" | "RUNNING" | "SKIPPED";
111+
}>
109112
> = props => {
110113
const [showPopover, setShowPopover] = useState(false);
111114
const handleOpenChange = (newOpen: boolean) => {
@@ -122,14 +125,15 @@ function TaskStatus0({ task, loading }: { task: TasksDbModel & TaskStats; loadin
122125
<div className={"overflow-y-auto"} style={{ maxHeight: "60vh" }}>
123126
{task.stats ? (
124127
<TaskStatusResultTable
128+
error={task.error ?? ""}
125129
stats={Object.entries(task.stats).reduce((arr, v) => {
126130
const o = { key: v[0], stream: v[0], ...(v[1] as any) };
127131
arr.push(o);
128132
return arr;
129133
}, [] as any[])}
130134
/>
131135
) : (
132-
<div className={"whitespace-pre-wrap font-mono text-xs"}>{task.description}</div>
136+
<div className={"whitespace-pre-wrap font-mono text-xs"}>{task.error || task.description}</div>
133137
)}
134138
</div>
135139
<div className={"flex flex-row w-full gap-2 justify-end pt-2"}>
@@ -162,7 +166,7 @@ function TaskStatus0({ task, loading }: { task: TasksDbModel & TaskStats; loadin
162166
<PlayCircle style={{ color: "blue" }} />
163167
) : props.status === "SKIPPED" ? (
164168
<XCircle style={{ color: "orange" }} />
165-
) : props.status === "CANCELLED" ? (
169+
) : props.status === "CANCELLED" || props.status === "TIME_EXCEEDED" ? (
166170
<XCircle style={{ color: "gray" }} />
167171
) : (
168172
<XCircle style={{ color: "red" }} />
@@ -217,10 +221,11 @@ function TaskStatus0({ task, loading }: { task: TasksDbModel & TaskStats; loadin
217221
</SyncStatus>
218222
);
219223
case "CANCELLED":
224+
case "TIME_EXCEEDED":
220225
return (
221226
<SyncStatus status={task.status}>
222227
<Tag style={{ marginRight: 0 }}>
223-
CANCELLED <FaExternalLinkAlt className={"inline ml-0.5 w-2.5 h-2.5"} />
228+
{task.status} <FaExternalLinkAlt className={"inline ml-0.5 w-2.5 h-2.5"} />
224229
</Tag>
225230
<span className={"text-xxs text-gray-500"}>show stats</span>
226231
</SyncStatus>
@@ -240,7 +245,7 @@ function TaskStatus0({ task, loading }: { task: TasksDbModel & TaskStats; loadin
240245
<Tag color={"red"} style={{ marginRight: 0 }}>
241246
FAILED <FaExternalLinkAlt className={"inline ml-0.5 w-2.5 h-2.5"} />
242247
</Tag>
243-
<span className={"text-xxs text-gray-500"}>show error</span>
248+
<span className={"text-xxs text-gray-500"}>show details</span>
244249
</SyncStatus>
245250
);
246251
case "RUNNING":
@@ -259,7 +264,7 @@ function TaskStatus0({ task, loading }: { task: TasksDbModel & TaskStats; loadin
259264

260265
export const TaskStatus = React.memo(TaskStatus0, (p, n) => hash(p) === hash(n));
261266

262-
function TaskStatusResultTable({ stats }: { stats: any[] }) {
267+
function TaskStatusResultTable({ stats, error }: { stats: any[]; error?: string }) {
263268
const columns: ColumnType<any>[] = [
264269
{
265270
title: "Stream",
@@ -277,8 +282,8 @@ function TaskStatusResultTable({ stats }: { stats: any[] }) {
277282
return <Tag color="green">SUCCESS</Tag>;
278283
} else if (record.status === "PARTIAL") {
279284
return <Tag color="orange">PARTIAL</Tag>;
280-
} else if (record.status === "CANCELLED") {
281-
return <Tag>CANCELLED</Tag>;
285+
} else if (record.status === "CANCELLED" || record.status === "TIME_EXCEEDED") {
286+
return <Tag>{record.status}</Tag>;
282287
} else if (record.status === "PENDING") {
283288
return <Tag>PENDING</Tag>;
284289
} else if (record.status === "RUNNING") {
@@ -308,18 +313,31 @@ function TaskStatusResultTable({ stats }: { stats: any[] }) {
308313
},
309314
];
310315
return (
311-
<Table
312-
size={"small"}
313-
columns={columns}
314-
dataSource={stats}
315-
pagination={false}
316-
expandable={{
317-
rowExpandable: record => record.status === "FAILED" || record.status === "PARTIAL",
318-
expandedRowRender: record => {
319-
return <pre className={"text-xs text-red-600 break-all whitespace-pre-wrap"}>{record.error}</pre>;
320-
},
321-
}}
322-
/>
316+
<div className={"flex flex-col gap-1"}>
317+
{error && (
318+
<div className={"p-2 max-w-5xl"}>
319+
<b>Abort Reason</b>:<br />
320+
<span
321+
className="text-red-600 whitespace-pre-wrap"
322+
dangerouslySetInnerHTML={{
323+
__html: escape(error),
324+
}}
325+
/>
326+
</div>
327+
)}
328+
<Table
329+
size={"small"}
330+
columns={columns}
331+
dataSource={stats}
332+
pagination={false}
333+
expandable={{
334+
rowExpandable: record => record.status === "FAILED" || record.status === "PARTIAL",
335+
expandedRowRender: record => {
336+
return <pre className={"text-xs text-red-600 break-all whitespace-pre-wrap"}>{record.error}</pre>;
337+
},
338+
}}
339+
/>
340+
</div>
323341
);
324342
}
325343

webapps/console/pages/_app.tsx

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -446,16 +446,21 @@ const WorkspaceLoader: React.FC<
446446
const workspace = useLoadedWorkspace(workspaceIdOrSlug);
447447

448448
useEffect(() => {
449-
if (workspace?.id) {
450-
analytics.page("Workspace Page", {
451-
context: { workspaceId: workspace.id, groupId: workspace.id },
452-
});
449+
if (workspace?.name) {
453450
const newTitle = `Jitsu - ${workspace.name}`;
454451
if (document.title !== newTitle) {
455452
document.title = newTitle;
456453
}
457454
}
458-
}, [analytics, router.asPath, workspace?.id, workspace?.name]);
455+
});
456+
457+
useEffect(() => {
458+
if (workspace?.id) {
459+
analytics.page("Workspace Page", {
460+
context: { workspaceId: workspace.id, groupId: workspace.id },
461+
});
462+
}
463+
}, [analytics, router.asPath, workspace?.id]);
459464

460465
/* eslint-disable react-hooks/exhaustive-deps */
461466
//user may be a new object on each render while being the same user

webapps/console/pages/api/[workspaceId]/sources/tasks.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,8 @@ const aggregatedResultType = z.object({
2020
sync_id: z.string(),
2121
task_id: z.string(),
2222
status: z.string(),
23-
description: z.string(),
23+
description: z.string().nullish(),
24+
error: z.string().nullish(),
2425
started_by: z.any().optional(),
2526
started_at: z.date(),
2627
updated_at: z.date(),
@@ -75,6 +76,7 @@ export default createRoute()
7576
`select distinct sync_id as sync_id,
7677
last_value(task_id) over ( partition by sync_id order by case when status = 'SKIPPED' then '2020-01-01' else started_at end RANGE BETWEEN unbounded preceding and unbounded following) as task_id,
7778
last_value(status) over ( partition by sync_id order by case when status = 'SKIPPED' then '2020-01-01' else started_at end RANGE BETWEEN unbounded preceding and unbounded following) as status,
79+
last_value(error) over ( partition by sync_id order by case when status = 'SKIPPED' then '2020-01-01' else started_at end RANGE BETWEEN unbounded preceding and unbounded following) as error,
7880
last_value(description) over ( partition by sync_id order by case when status = 'SKIPPED' then '2020-01-01' else started_at end RANGE BETWEEN unbounded preceding and unbounded following) as description,
7981
last_value(started_at) over ( partition by sync_id order by case when status = 'SKIPPED' then '2020-01-01' else started_at end RANGE BETWEEN unbounded preceding and unbounded following) as started_at,
8082
last_value(updated_at) over ( partition by sync_id order by case when status = 'SKIPPED' then '2020-01-01' else started_at end RANGE BETWEEN unbounded preceding and unbounded following) as updated_at
@@ -87,6 +89,7 @@ from newjitsu.source_task where sync_id = ANY($1::text[])`,
8789
task_id: r.task_id,
8890
status: r.status,
8991
description: r.description,
92+
error: r.error,
9093
started_at: r.started_at,
9194
updated_at: r.updated_at,
9295
};

webapps/console/prisma/schema.prisma

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -273,6 +273,7 @@ model source_task {
273273
status String
274274
description String?
275275
metrics Json?
276+
error String?
276277
277278
@@index(sync_id)
278279
@@index(started_at)

0 commit comments

Comments
 (0)