feat(discord) : sync latest Lunaris version and report status
CI / Verify (push) Successful in 1m18s
CI / Build immutable images and deploy (push) Successful in 1m50s

This commit is contained in:
2026-09-09 17:38:40 +07:00 Unverified
parent d85a48be25
commit 289c17808f
5 changed files with 51 additions and 12 deletions
+42 -9
View File
@@ -7,7 +7,10 @@ import {
} from "discord.js";
import { closeDb } from "@/db/client";
import { processCatalogSync } from "@/lib/catalog/sync";
import {
getLatestLunarisVersion,
processCatalogSync,
} from "@/lib/catalog/sync";
import {
compareLunarisVersions,
parseLunarisVersionChange,
@@ -54,6 +57,7 @@ function wait(milliseconds: number, signal: AbortSignal): Promise<boolean> {
const token = required("DISCORD_BOT_TOKEN");
const channelId = required("DISCORD_CHANNEL_ID");
const logChannelId = required("DISCORD_LOG_CHANNEL_ID");
const shutdown = new AbortController();
const client = new Client({
intents: [
@@ -66,40 +70,68 @@ const client = new Client({
let pendingVersion: string | null = null;
let runner: Promise<void> | null = null;
async function syncWithRetry(version: string): Promise<void> {
async function notify(event: string, details: Record<string, unknown> = {}): Promise<void> {
try {
const channel = await client.channels.fetch(logChannelId);
if (!channel?.isSendable()) {
log("notification_failed", { event, error: "Discord log channel is not sendable." });
return;
}
await channel.send(`**Lunaris catalog worker — ${event}**\n\`\`\`json\n${JSON.stringify(details, null, 2)}\n\`\`\``);
} catch (cause) {
log("notification_failed", {
event,
error: cause instanceof Error ? cause.message : String(cause),
});
}
}
async function syncWithRetry(announcedVersion: string): Promise<void> {
for (let attempt = 0; attempt < RETRY_DELAYS_MS.length; attempt += 1) {
if (shutdown.signal.aborted) return;
if (
pendingVersion &&
compareLunarisVersions(pendingVersion, version) > 0
compareLunarisVersions(pendingVersion, announcedVersion) > 0
) {
log("sync_superseded", { version, pendingVersion });
log("sync_superseded", { announcedVersion, pendingVersion });
return;
}
if (!(await wait(RETRY_DELAYS_MS[attempt], shutdown.signal))) return;
if (
pendingVersion &&
compareLunarisVersions(pendingVersion, version) > 0
compareLunarisVersions(pendingVersion, announcedVersion) > 0
) {
log("sync_superseded", { version, pendingVersion });
log("sync_superseded", { announcedVersion, pendingVersion });
return;
}
try {
log("sync_started", { version, attempt: attempt + 1 });
const version = await getLatestLunarisVersion();
const details = { announcedVersion, version, attempt: attempt + 1 };
log("sync_started", details);
await notify("sync started", details);
const result = await processCatalogSync(version);
log(result === "synced" ? "sync_completed" : "sync_ignored", {
announcedVersion,
version,
reason: result === "unchanged" ? "current-or-older" : undefined,
});
await notify(result === "synced" ? "sync completed" : "already current", {
announcedVersion,
version,
});
return;
} catch (cause) {
const message = cause instanceof Error ? cause.message : String(cause);
if (attempt === RETRY_DELAYS_MS.length - 1) {
log("sync_failed", { version, attempts: attempt + 1, error: message });
const details = { announcedVersion, attempts: attempt + 1, error: message };
log("sync_failed", details);
await notify("sync failed", details);
return;
}
log("sync_retrying", { version, attempt: attempt + 1, error: message });
const details = { announcedVersion, attempt: attempt + 1, error: message };
log("sync_retrying", details);
await notify("sync retrying", details);
}
}
}
@@ -153,6 +185,7 @@ try {
await Promise.race([ready, stopped]);
if (!shutdown.signal.aborted) {
log("discord_ready", { userId: client.user?.id, channelId });
await notify("worker ready", { userId: client.user?.id, channelId });
const channel = await client.channels.fetch(channelId);
if (