Refactor queue management to use lazy initialization and improve Redis connection handling

- Updated queue and QueueEvents initialization to be lazy, preventing unnecessary Redis connections during the build process.
- Refactored queue access methods to ensure consistent connection handling across the application.
- Enhanced error handling for Redis connections during production builds to reduce log noise.
This commit is contained in:
TheOnlyMace
2026-07-22 21:38:56 +02:00
parent b7cf505ca4
commit 6a223892dd
6 changed files with 88 additions and 43 deletions

View File

@@ -8,6 +8,11 @@ import { redis } from './redis';
* drawing winners, restoring a guild backup) is enqueued here and picked up
* by the bot's existing workers - the WebUI never talks to Discord directly
* for these actions.
*
* Queues and QueueEvents are created lazily on first use. Eager construction
* at import time would open Redis connections during `next build` (where
* Redis is intentionally unavailable), flooding the build log with
* ECONNREFUSED errors.
*/
export const giveawayQueueName = 'giveaways';
export const scheduleQueueName = 'schedules';
@@ -24,43 +29,68 @@ const globalForQueues = globalThis as unknown as {
__nexumiSuggestionsQueueEvents?: QueueEvents;
};
export const giveawayQueue: Queue =
globalForQueues.__nexumiGiveawayQueue ?? new Queue(giveawayQueueName, { connection: redis });
function queueConnection() {
return redis;
}
export const scheduleQueue: Queue =
globalForQueues.__nexumiScheduleQueue ?? new Queue(scheduleQueueName, { connection: redis });
/** QueueEvents needs its own connection; duplicate inherits lazyConnect. */
function queueEventsConnection() {
return redis.duplicate();
}
export const guildBackupQueue: Queue =
globalForQueues.__nexumiGuildBackupQueue ?? new Queue(guildBackupQueueName, { connection: redis });
export function getGiveawayQueue(): Queue {
globalForQueues.__nexumiGiveawayQueue ??= new Queue(giveawayQueueName, {
connection: queueConnection()
});
return globalForQueues.__nexumiGiveawayQueue;
}
export const suggestionsQueue: Queue =
globalForQueues.__nexumiSuggestionsQueue ?? new Queue(suggestionsQueueName, { connection: redis });
export function getScheduleQueue(): Queue {
globalForQueues.__nexumiScheduleQueue ??= new Queue(scheduleQueueName, {
connection: queueConnection()
});
return globalForQueues.__nexumiScheduleQueue;
}
export function getGuildBackupQueue(): Queue {
globalForQueues.__nexumiGuildBackupQueue ??= new Queue(guildBackupQueueName, {
connection: queueConnection()
});
return globalForQueues.__nexumiGuildBackupQueue;
}
export function getSuggestionsQueue(): Queue {
globalForQueues.__nexumiSuggestionsQueue ??= new Queue(suggestionsQueueName, {
connection: queueConnection()
});
return globalForQueues.__nexumiSuggestionsQueue;
}
/**
* QueueEvents instances are only needed for jobs where the dashboard needs
* to wait for the bot to finish (e.g. ending a giveaway so the winners list
* is immediately visible). They open their own Redis connection, so they are
* cached on the global object the same way as the queues themselves.
* is immediately visible).
*/
export const giveawayQueueEvents: QueueEvents =
globalForQueues.__nexumiGiveawayQueueEvents ??
new QueueEvents(giveawayQueueName, { connection: redis.duplicate() });
export function getGiveawayQueueEvents(): QueueEvents {
globalForQueues.__nexumiGiveawayQueueEvents ??= new QueueEvents(giveawayQueueName, {
connection: queueEventsConnection()
});
return globalForQueues.__nexumiGiveawayQueueEvents;
}
export const guildBackupQueueEvents: QueueEvents =
globalForQueues.__nexumiGuildBackupQueueEvents ??
new QueueEvents(guildBackupQueueName, { connection: redis.duplicate() });
export function getGuildBackupQueueEvents(): QueueEvents {
globalForQueues.__nexumiGuildBackupQueueEvents ??= new QueueEvents(guildBackupQueueName, {
connection: queueEventsConnection()
});
return globalForQueues.__nexumiGuildBackupQueueEvents;
}
export const suggestionsQueueEvents: QueueEvents =
globalForQueues.__nexumiSuggestionsQueueEvents ??
new QueueEvents(suggestionsQueueName, { connection: redis.duplicate() });
globalForQueues.__nexumiGiveawayQueue = giveawayQueue;
globalForQueues.__nexumiScheduleQueue = scheduleQueue;
globalForQueues.__nexumiGuildBackupQueue = guildBackupQueue;
globalForQueues.__nexumiSuggestionsQueue = suggestionsQueue;
globalForQueues.__nexumiGiveawayQueueEvents = giveawayQueueEvents;
globalForQueues.__nexumiGuildBackupQueueEvents = guildBackupQueueEvents;
globalForQueues.__nexumiSuggestionsQueueEvents = suggestionsQueueEvents;
export function getSuggestionsQueueEvents(): QueueEvents {
globalForQueues.__nexumiSuggestionsQueueEvents ??= new QueueEvents(suggestionsQueueName, {
connection: queueEventsConnection()
});
return globalForQueues.__nexumiSuggestionsQueueEvents;
}
const DEFAULT_WAIT_TIMEOUT_MS = 15_000;