feat(client): show digital sync failure details

This commit is contained in:
baiyanyun
2026-06-07 01:05:49 +08:00
parent ac1a6fd0e6
commit 0672e82fc7
10 changed files with 280 additions and 126 deletions

View File

@@ -33,6 +33,18 @@ interface OutboxRow {
last_attempt_at?: string | null;
}
export interface DigitalEmployeeSyncFailure {
id: string;
entityType: string;
entityId: string;
operation: string;
attempts: number;
lastAttemptAt: string | null;
error: string | null;
createdAt: string;
updatedAt: string;
}
interface SyncAck {
outbox_id?: string;
id?: string;
@@ -59,6 +71,7 @@ export interface DigitalEmployeeSyncStatus {
failed: number;
lastSyncAt: string | null;
lastSyncError: string | null;
recentFailures: DigitalEmployeeSyncFailure[];
}
export function startDigitalEmployeeSyncWorker(): void {
@@ -94,6 +107,7 @@ export function getDigitalEmployeeSyncStatus(): DigitalEmployeeSyncStatus {
failed: countOutbox("failed"),
lastSyncAt,
lastSyncError,
recentFailures: readRecentFailures(),
};
}
@@ -369,6 +383,45 @@ function countOutbox(status: string): number {
return row?.count ?? 0;
}
function readRecentFailures(limit = 3): DigitalEmployeeSyncFailure[] {
const db = getDb();
if (!db) return [];
const rows = db
.prepare(
`
SELECT id, entity_type, entity_id, operation, attempts,
last_attempt_at, error, created_at, updated_at
FROM digital_sync_outbox
WHERE status = 'failed'
ORDER BY COALESCE(last_attempt_at, updated_at, created_at) DESC
LIMIT ?
`,
)
.all(limit) as Array<{
id: string;
entity_type: string;
entity_id: string;
operation: string;
attempts: number;
last_attempt_at: string | null;
error: string | null;
created_at: string;
updated_at: string;
}>;
return rows.map((row) => ({
id: row.id,
entityType: row.entity_type,
entityId: row.entity_id,
operation: row.operation,
attempts: row.attempts,
lastAttemptAt: row.last_attempt_at,
error: row.error,
createdAt: row.created_at,
updatedAt: row.updated_at,
}));
}
function entityTable(entityType: string): string | null {
switch (entityType) {
case "plan":