Fix Discord pick announcements arriving out of order and add 429 retry #51
3 changed files with 55 additions and 33 deletions
|
|
@ -827,23 +827,8 @@ export async function executeAutoPick(params: {
|
|||
logger.error("[AutoPick] Error updating Brackt EVs after pick:", error);
|
||||
}
|
||||
|
||||
// Check if next team has autodraft enabled and trigger immediately
|
||||
// Only run the chain from the top-level call to prevent recursion
|
||||
if (!isDraftComplete && params.chainEnabled !== false) {
|
||||
await checkAndTriggerNextAutodraft({
|
||||
seasonId,
|
||||
nextPickNumber,
|
||||
totalTeams,
|
||||
draftSlots,
|
||||
db,
|
||||
});
|
||||
|
||||
// Fire-and-forget: sendOnTheClockEmail fetches the current pick number from
|
||||
// the DB itself, so it always sees the post-chain state without blocking here.
|
||||
sendOnTheClockEmail({ seasonId, totalTeams, draftSlots, db })
|
||||
.catch((err) => logger.error("[AutoPick] On-the-clock email failed:", err));
|
||||
}
|
||||
|
||||
// Announce before triggering the chain so Discord messages arrive in pick-number
|
||||
// order. If the chain ran first, chained picks would announce before this one.
|
||||
const pickedSlot = draftSlots.find((s) => s.teamId === teamId);
|
||||
if (!pickedSlot) {
|
||||
logger.warn(`[AutoPick] Skipping Discord pick announcement: no draft slot found for team ${teamId}`);
|
||||
|
|
@ -865,6 +850,23 @@ export async function executeAutoPick(params: {
|
|||
}).catch((err) => logger.error("[AutoPick] Discord pick announcement failed:", err));
|
||||
}
|
||||
|
||||
// Check if next team has autodraft enabled and trigger immediately
|
||||
// Only run the chain from the top-level call to prevent recursion
|
||||
if (!isDraftComplete && params.chainEnabled !== false) {
|
||||
await checkAndTriggerNextAutodraft({
|
||||
seasonId,
|
||||
nextPickNumber,
|
||||
totalTeams,
|
||||
draftSlots,
|
||||
db,
|
||||
});
|
||||
|
||||
// Fire-and-forget: sendOnTheClockEmail fetches the current pick number from
|
||||
// the DB itself, so it always sees the post-chain state without blocking here.
|
||||
sendOnTheClockEmail({ seasonId, totalTeams, draftSlots, db })
|
||||
.catch((err) => logger.error("[AutoPick] On-the-clock email failed:", err));
|
||||
}
|
||||
|
||||
return {
|
||||
success: true,
|
||||
pick: draftPick,
|
||||
|
|
|
|||
|
|
@ -303,6 +303,24 @@ export async function action(args: ActionFunctionArgs) {
|
|||
logger.error("Socket.IO error:", error);
|
||||
}
|
||||
|
||||
// Announce before triggering the chain so Discord messages arrive in pick-number
|
||||
// order. If the chain ran first, chained picks would announce before this one.
|
||||
notifyPickMadeOnDiscord({
|
||||
seasonId,
|
||||
leagueId: season.leagueId,
|
||||
pickedTeamName: currentDraftSlot.team.name,
|
||||
participantName: participant.name,
|
||||
sportName: participant.sportsSeason.sport.name,
|
||||
pickNumber: currentPickNumber,
|
||||
nextPickNumber,
|
||||
round: currentRound,
|
||||
rawPickInRound,
|
||||
isDraftComplete,
|
||||
totalTeams,
|
||||
draftSlots: draftSlots.map((s) => ({ teamId: s.teamId, draftOrder: s.draftOrder })),
|
||||
db,
|
||||
}).catch((err) => logger.error("Discord pick announcement failed:", err));
|
||||
|
||||
// Check if next team has autodraft enabled and trigger immediately
|
||||
if (!isDraftComplete) {
|
||||
try {
|
||||
|
|
@ -331,22 +349,6 @@ export async function action(args: ActionFunctionArgs) {
|
|||
.catch((err) => logger.error("On-the-clock email failed:", err));
|
||||
}
|
||||
|
||||
notifyPickMadeOnDiscord({
|
||||
seasonId,
|
||||
leagueId: season.leagueId,
|
||||
pickedTeamName: currentDraftSlot.team.name,
|
||||
participantName: participant.name,
|
||||
sportName: participant.sportsSeason.sport.name,
|
||||
pickNumber: currentPickNumber,
|
||||
nextPickNumber,
|
||||
round: currentRound,
|
||||
rawPickInRound,
|
||||
isDraftComplete,
|
||||
totalTeams,
|
||||
draftSlots: draftSlots.map((s) => ({ teamId: s.teamId, draftOrder: s.draftOrder })),
|
||||
db,
|
||||
}).catch((err) => logger.error("Discord pick announcement failed:", err));
|
||||
|
||||
return Response.json({
|
||||
success: true,
|
||||
pick: draftPick,
|
||||
|
|
|
|||
|
|
@ -24,6 +24,24 @@ export async function sendDiscordWebhook(
|
|||
body: JSON.stringify(payload),
|
||||
});
|
||||
|
||||
if (response.status === 429) {
|
||||
// Cap at 10 s so awaited callers (e.g. settings actions) are never hung for
|
||||
// a full Discord global-rate-limit window. Use || 1 instead of ?? 1 so that
|
||||
// NaN (non-numeric header) and 0 both fall back to a 1-second default.
|
||||
const retryAfterSeconds = Math.min(Number(response.headers.get("Retry-After")) || 1, 10);
|
||||
await new Promise((r) => setTimeout(r, retryAfterSeconds * 1000));
|
||||
const retry = await fetch(webhookUrl, {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify(payload),
|
||||
});
|
||||
if (!retry.ok) {
|
||||
const text = await retry.text().catch(() => "");
|
||||
throw new Error(`Discord webhook failed after retry: ${retry.status} ${text}`);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (!response.ok) {
|
||||
const text = await response.text().catch(() => "");
|
||||
throw new Error(`Discord webhook failed: ${response.status} ${text}`);
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue