fixed queue close
This commit is contained in:
parent
c048e00d7f
commit
dbfa80b2a2
2 changed files with 84 additions and 121 deletions
|
|
@ -1,13 +1,13 @@
|
|||
import { getLogger } from '@stock-bot/logger';
|
||||
import { QueueRateLimiter } from './rate-limiter';
|
||||
import { Queue, type QueueWorkerConfig } from './queue';
|
||||
import { CacheProvider, createCache } from '@stock-bot/cache';
|
||||
import type {
|
||||
QueueManagerConfig,
|
||||
QueueOptions,
|
||||
GlobalStats,
|
||||
import { getLogger } from '@stock-bot/logger';
|
||||
import { Queue, type QueueWorkerConfig } from './queue';
|
||||
import { QueueRateLimiter } from './rate-limiter';
|
||||
import type {
|
||||
GlobalStats,
|
||||
QueueManagerConfig,
|
||||
QueueOptions,
|
||||
QueueStats,
|
||||
RateLimitRule
|
||||
RateLimitRule,
|
||||
} from './types';
|
||||
import { getRedisConnection } from './utils';
|
||||
|
||||
|
|
@ -30,7 +30,7 @@ export class QueueManager {
|
|||
private constructor(config: QueueManagerConfig) {
|
||||
this.config = config;
|
||||
this.redisConnection = getRedisConnection(config.redis);
|
||||
|
||||
|
||||
// Initialize rate limiter if rules are provided
|
||||
if (config.rateLimitRules && config.rateLimitRules.length > 0) {
|
||||
this.rateLimiter = new QueueRateLimiter(this.redisConnection);
|
||||
|
|
@ -40,7 +40,7 @@ export class QueueManager {
|
|||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
logger.info('QueueManager singleton initialized', {
|
||||
redis: `${config.redis.host}:${config.redis.port}`,
|
||||
});
|
||||
|
|
@ -52,9 +52,7 @@ export class QueueManager {
|
|||
*/
|
||||
static getInstance(): QueueManager {
|
||||
if (!QueueManager.instance) {
|
||||
throw new Error(
|
||||
'QueueManager not initialized. Call QueueManager.initialize(config) first.'
|
||||
);
|
||||
throw new Error('QueueManager not initialized. Call QueueManager.initialize(config) first.');
|
||||
}
|
||||
return QueueManager.instance;
|
||||
}
|
||||
|
|
@ -80,14 +78,14 @@ export class QueueManager {
|
|||
if (QueueManager.instance) {
|
||||
return QueueManager.instance;
|
||||
}
|
||||
|
||||
|
||||
if (!config) {
|
||||
throw new Error(
|
||||
'QueueManager not initialized and no config provided. ' +
|
||||
'Either call initialize(config) first or provide config to getOrInitialize(config).'
|
||||
'Either call initialize(config) first or provide config to getOrInitialize(config).'
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
return QueueManager.initialize(config);
|
||||
}
|
||||
|
||||
|
|
@ -135,8 +133,8 @@ export class QueueManager {
|
|||
};
|
||||
|
||||
const queue = new Queue(
|
||||
queueName,
|
||||
this.config.redis,
|
||||
queueName,
|
||||
this.config.redis,
|
||||
mergedOptions.defaultJobOptions || {},
|
||||
queueConfig
|
||||
);
|
||||
|
|
@ -158,10 +156,10 @@ export class QueueManager {
|
|||
});
|
||||
}
|
||||
|
||||
logger.info('Queue created with batch cache', {
|
||||
queueName,
|
||||
logger.info('Queue created with batch cache', {
|
||||
queueName,
|
||||
workers: mergedOptions.workers || 0,
|
||||
concurrency: mergedOptions.concurrency || 1
|
||||
concurrency: mergedOptions.concurrency || 1,
|
||||
});
|
||||
|
||||
return queue;
|
||||
|
|
@ -232,7 +230,7 @@ export class QueueManager {
|
|||
for (const [queueName, queue] of this.queues) {
|
||||
const stats = await queue.getStats();
|
||||
queueStats[queueName] = stats;
|
||||
|
||||
|
||||
totalJobs += stats.waiting + stats.active + stats.completed + stats.failed + stats.delayed;
|
||||
totalWorkers += stats.workers || 0;
|
||||
}
|
||||
|
|
@ -269,7 +267,11 @@ export class QueueManager {
|
|||
/**
|
||||
* Check rate limits for a job
|
||||
*/
|
||||
async checkRateLimit(queueName: string, handler: string, operation: string): Promise<{
|
||||
async checkRateLimit(
|
||||
queueName: string,
|
||||
handler: string,
|
||||
operation: string
|
||||
): Promise<{
|
||||
allowed: boolean;
|
||||
retryAfter?: number;
|
||||
remainingPoints?: number;
|
||||
|
|
@ -278,7 +280,7 @@ export class QueueManager {
|
|||
if (!this.rateLimiter) {
|
||||
return { allowed: true };
|
||||
}
|
||||
|
||||
|
||||
return await this.rateLimiter.checkLimit(queueName, handler, operation);
|
||||
}
|
||||
|
||||
|
|
@ -293,7 +295,7 @@ export class QueueManager {
|
|||
operation,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
return await this.rateLimiter.getStatus(queueName, handler, operation);
|
||||
}
|
||||
|
||||
|
|
@ -323,7 +325,7 @@ export class QueueManager {
|
|||
if (!queue) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
await queue.pause();
|
||||
return true;
|
||||
}
|
||||
|
|
@ -336,7 +338,7 @@ export class QueueManager {
|
|||
if (!queue) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
await queue.resume();
|
||||
return true;
|
||||
}
|
||||
|
|
@ -354,18 +356,17 @@ export class QueueManager {
|
|||
* Clean all queues
|
||||
*/
|
||||
async cleanAll(
|
||||
grace: number = 0,
|
||||
limit: number = 100,
|
||||
grace: number = 0,
|
||||
limit: number = 100,
|
||||
type: 'completed' | 'failed' = 'completed'
|
||||
): Promise<void> {
|
||||
const cleanPromises = Array.from(this.queues.values()).map(queue =>
|
||||
const cleanPromises = Array.from(this.queues.values()).map(queue =>
|
||||
queue.clean(grace, limit, type)
|
||||
);
|
||||
await Promise.all(cleanPromises);
|
||||
logger.info('All queues cleaned', { type, grace, limit });
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Shutdown all queues and workers (thread-safe)
|
||||
*/
|
||||
|
|
@ -393,15 +394,15 @@ export class QueueManager {
|
|||
private async performShutdown(): Promise<void> {
|
||||
try {
|
||||
// Close all queues (this now includes workers since they're managed by Queue class)
|
||||
const queueShutdownPromises = Array.from(this.queues.values()).map(async (queue) => {
|
||||
const queueShutdownPromises = Array.from(this.queues.values()).map(async queue => {
|
||||
try {
|
||||
// Add timeout to queue.close() to prevent hanging
|
||||
const closePromise = queue.close();
|
||||
const timeoutPromise = new Promise<never>((_, reject) =>
|
||||
setTimeout(() => reject(new Error('Queue close timeout')), 100)
|
||||
);
|
||||
|
||||
await Promise.race([closePromise, timeoutPromise]);
|
||||
await queue.close();
|
||||
// const timeoutPromise = new Promise<never>((_, reject) =>
|
||||
// setTimeout(() => reject(new Error('Queue close timeout')), 100)
|
||||
// );
|
||||
|
||||
// await Promise.race([closePromise, timeoutPromise]);
|
||||
} catch (error) {
|
||||
logger.warn('Error closing queue', { error: (error as Error).message });
|
||||
}
|
||||
|
|
@ -410,7 +411,7 @@ export class QueueManager {
|
|||
await Promise.all(queueShutdownPromises);
|
||||
|
||||
// Close all caches
|
||||
const cacheShutdownPromises = Array.from(this.caches.values()).map(async (cache) => {
|
||||
const cacheShutdownPromises = Array.from(this.caches.values()).map(async cache => {
|
||||
try {
|
||||
// Clear cache before shutdown
|
||||
await cache.clear();
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue