msg: retry web/telegram sends and add regression tests

This commit is contained in:
Peter Steinberger
2025-12-09 17:23:04 +00:00
parent f9370718bc
commit d04f7fc6e9
3 changed files with 169 additions and 30 deletions

View File

@@ -45,6 +45,27 @@ export async function sendMessageTelegram(
const api = opts.api ?? bot?.api;
const mediaUrl = opts.mediaUrl?.trim();
const sleep = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms));
const sendWithRetry = async <T>(fn: () => Promise<T>, label: string) => {
let lastErr: unknown;
for (let attempt = 1; attempt <= 3; attempt++) {
try {
return await fn();
} catch (err) {
lastErr = err;
const terminal = attempt === 3 ||
!/429|timeout|connect|reset|closed|unavailable|temporarily/i.test(String(err ?? ""));
if (terminal) break;
const backoff = 400 * attempt;
if (opts.verbose) {
console.warn(`telegram send retry ${attempt}/2 for ${label} in ${backoff}ms: ${String(err)}`);
}
await sleep(backoff);
}
}
throw lastErr ?? new Error(`Telegram send failed (${label})`);
};
if (mediaUrl) {
const media = await loadWebMedia(mediaUrl, opts.maxBytes);
const kind = mediaKindFromMime(media.contentType ?? undefined);
@@ -59,13 +80,13 @@ export async function sendMessageTelegram(
| Awaited<ReturnType<typeof api.sendAudio>>
| Awaited<ReturnType<typeof api.sendDocument>>;
if (kind === "image") {
result = await api.sendPhoto(chatId, file, { caption });
result = await sendWithRetry(() => api.sendPhoto(chatId, file, { caption }), "photo");
} else if (kind === "video") {
result = await api.sendVideo(chatId, file, { caption });
result = await sendWithRetry(() => api.sendVideo(chatId, file, { caption }), "video");
} else if (kind === "audio") {
result = await api.sendAudio(chatId, file, { caption });
result = await sendWithRetry(() => api.sendAudio(chatId, file, { caption }), "audio");
} else {
result = await api.sendDocument(chatId, file, { caption });
result = await sendWithRetry(() => api.sendDocument(chatId, file, { caption }), "document");
}
const messageId = String(result?.message_id ?? "unknown");
return { messageId, chatId: String(result?.chat?.id ?? chatId) };
@@ -74,9 +95,10 @@ export async function sendMessageTelegram(
if (!text || !text.trim()) {
throw new Error("Message must be non-empty for Telegram sends");
}
const res = await api.sendMessage(chatId, text, {
parse_mode: "Markdown",
});
const res = await sendWithRetry(
() => api.sendMessage(chatId, text, { parse_mode: "Markdown" }),
"message",
);
const messageId = String(res?.message_id ?? "unknown");
return { messageId, chatId: String(res?.chat?.id ?? chatId) };
}