mirror of
https://github.com/xCyanGrizzly/DragonsStash.git
synced 2026-05-10 22:01:16 +00:00
feat: add retry server actions for skipped/failed packages
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -177,3 +177,148 @@ export async function setPreviewFromExtract(
|
|||||||
return { success: false, error: "Failed to set preview from archive image" };
|
return { success: false, error: "Failed to set preview from archive image" };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function retrySkippedPackageAction(
|
||||||
|
id: string
|
||||||
|
): Promise<ActionResult> {
|
||||||
|
const session = await auth();
|
||||||
|
if (!session?.user?.id) return { success: false, error: "Unauthorized" };
|
||||||
|
|
||||||
|
try {
|
||||||
|
const skipped = await prisma.skippedPackage.findUnique({
|
||||||
|
where: { id },
|
||||||
|
});
|
||||||
|
if (!skipped) return { success: false, error: "Skipped package not found" };
|
||||||
|
|
||||||
|
// Find the AccountChannelMap and reset watermark if needed
|
||||||
|
const mapping = await prisma.accountChannelMap.findUnique({
|
||||||
|
where: {
|
||||||
|
accountId_channelId: {
|
||||||
|
accountId: skipped.accountId,
|
||||||
|
channelId: skipped.sourceChannelId,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
if (mapping) {
|
||||||
|
const targetId = skipped.sourceMessageId - 1n;
|
||||||
|
|
||||||
|
// Only reset if the watermark is past this message
|
||||||
|
if (mapping.lastProcessedMessageId && mapping.lastProcessedMessageId >= skipped.sourceMessageId) {
|
||||||
|
await prisma.accountChannelMap.update({
|
||||||
|
where: { id: mapping.id },
|
||||||
|
data: { lastProcessedMessageId: targetId },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Also reset TopicProgress if this was a forum topic message
|
||||||
|
if (skipped.sourceTopicId) {
|
||||||
|
const topicProgress = await prisma.topicProgress.findFirst({
|
||||||
|
where: {
|
||||||
|
accountChannelMapId: mapping.id,
|
||||||
|
topicId: skipped.sourceTopicId,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
if (topicProgress && topicProgress.lastProcessedMessageId && topicProgress.lastProcessedMessageId >= skipped.sourceMessageId) {
|
||||||
|
await prisma.topicProgress.update({
|
||||||
|
where: { id: topicProgress.id },
|
||||||
|
data: { lastProcessedMessageId: targetId },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete the skip record
|
||||||
|
await prisma.skippedPackage.delete({ where: { id } });
|
||||||
|
|
||||||
|
revalidatePath("/stls");
|
||||||
|
return { success: true, data: undefined };
|
||||||
|
} catch {
|
||||||
|
return { success: false, error: "Failed to retry skipped package" };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function retryAllSkippedPackagesAction(
|
||||||
|
reason?: "SIZE_LIMIT" | "DOWNLOAD_FAILED" | "EXTRACT_FAILED" | "UPLOAD_FAILED"
|
||||||
|
): Promise<ActionResult> {
|
||||||
|
const session = await auth();
|
||||||
|
if (!session?.user?.id) return { success: false, error: "Unauthorized" };
|
||||||
|
|
||||||
|
try {
|
||||||
|
const where: Record<string, unknown> = {};
|
||||||
|
if (reason) where.reason = reason;
|
||||||
|
|
||||||
|
const skippedItems = await prisma.skippedPackage.findMany({ where });
|
||||||
|
|
||||||
|
if (skippedItems.length === 0) {
|
||||||
|
return { success: true, data: undefined };
|
||||||
|
}
|
||||||
|
|
||||||
|
// Group by (accountId, channelId) to find minimum messageId per channel
|
||||||
|
const channelResets = new Map<string, { mappingKey: { accountId: string; channelId: string }; minMessageId: bigint; topicResets: Map<bigint, bigint> }>();
|
||||||
|
|
||||||
|
for (const item of skippedItems) {
|
||||||
|
const key = `${item.accountId}:${item.sourceChannelId}`;
|
||||||
|
const existing = channelResets.get(key);
|
||||||
|
const targetId = item.sourceMessageId - 1n;
|
||||||
|
|
||||||
|
if (!existing) {
|
||||||
|
const topicResets = new Map<bigint, bigint>();
|
||||||
|
if (item.sourceTopicId) {
|
||||||
|
topicResets.set(item.sourceTopicId, targetId);
|
||||||
|
}
|
||||||
|
channelResets.set(key, {
|
||||||
|
mappingKey: { accountId: item.accountId, channelId: item.sourceChannelId },
|
||||||
|
minMessageId: targetId,
|
||||||
|
topicResets,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
if (targetId < existing.minMessageId) {
|
||||||
|
existing.minMessageId = targetId;
|
||||||
|
}
|
||||||
|
if (item.sourceTopicId) {
|
||||||
|
const existingTopic = existing.topicResets.get(item.sourceTopicId);
|
||||||
|
if (!existingTopic || targetId < existingTopic) {
|
||||||
|
existing.topicResets.set(item.sourceTopicId, targetId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reset watermarks
|
||||||
|
for (const reset of channelResets.values()) {
|
||||||
|
const mapping = await prisma.accountChannelMap.findUnique({
|
||||||
|
where: { accountId_channelId: reset.mappingKey },
|
||||||
|
});
|
||||||
|
if (!mapping) continue;
|
||||||
|
|
||||||
|
if (mapping.lastProcessedMessageId && mapping.lastProcessedMessageId > reset.minMessageId) {
|
||||||
|
await prisma.accountChannelMap.update({
|
||||||
|
where: { id: mapping.id },
|
||||||
|
data: { lastProcessedMessageId: reset.minMessageId },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reset topic progress
|
||||||
|
for (const [topicId, targetId] of reset.topicResets) {
|
||||||
|
const topicProgress = await prisma.topicProgress.findFirst({
|
||||||
|
where: { accountChannelMapId: mapping.id, topicId },
|
||||||
|
});
|
||||||
|
if (topicProgress && topicProgress.lastProcessedMessageId && topicProgress.lastProcessedMessageId > targetId) {
|
||||||
|
await prisma.topicProgress.update({
|
||||||
|
where: { id: topicProgress.id },
|
||||||
|
data: { lastProcessedMessageId: targetId },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete all matching skip records
|
||||||
|
await prisma.skippedPackage.deleteMany({ where });
|
||||||
|
|
||||||
|
revalidatePath("/stls");
|
||||||
|
return { success: true, data: undefined };
|
||||||
|
} catch {
|
||||||
|
return { success: false, error: "Failed to retry skipped packages" };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user