This commit is contained in:
Boki 2025-06-19 08:31:21 -04:00
parent d3ef73ae00
commit a2fa08de88
8 changed files with 72 additions and 68 deletions

View file

@ -1,17 +1,10 @@
import { Queue, type Job } from 'bullmq'; import { Queue, type Job } from 'bullmq';
import { getLogger } from '@stock-bot/logger'; import { getLogger } from '@stock-bot/logger';
import type { JobData } from './types'; import type { JobData, DLQConfig, RedisConfig } from './types';
import { getRedisConnection } from './utils'; import { getRedisConnection } from './utils';
const logger = getLogger('dlq-handler'); const logger = getLogger('dlq-handler');
export interface DLQConfig {
maxRetries?: number;
retryDelay?: number;
alertThreshold?: number;
cleanupAge?: number; // hours
}
export class DeadLetterQueueHandler { export class DeadLetterQueueHandler {
private dlq: Queue; private dlq: Queue;
private config: Required<DLQConfig>; private config: Required<DLQConfig>;
@ -19,7 +12,7 @@ export class DeadLetterQueueHandler {
constructor( constructor(
private mainQueue: Queue, private mainQueue: Queue,
private connection: any, private connection: RedisConfig,
config: DLQConfig = {} config: DLQConfig = {}
) { ) {
this.config = { this.config = {

View file

@ -1,21 +1,12 @@
export * from './batch-processor'; // Core exports
export * from './handler-registry'; export { Queue, type QueueWorkerConfig } from './queue';
export * from './queue-manager';
export * from './queue-factory';
export * from './types';
export * from './dlq-handler';
export * from './queue-metrics';
export * from './rate-limiter';
// Re-export commonly used functions
export { processBatchJob, processItems } from './batch-processor';
export { QueueManager } from './queue-manager'; export { QueueManager } from './queue-manager';
export { Queue, type QueueConfig } from './queue';
export { handlerRegistry } from './handler-registry'; export { handlerRegistry } from './handler-registry';
// Re-export queue factory functions // Batch processing
export { processBatchJob, processItems } from './batch-processor';
// Queue factory functions
export { export {
initializeQueueSystem, initializeQueueSystem,
getQueue, getQueue,
@ -25,17 +16,50 @@ export {
shutdownAllQueues shutdownAllQueues
} from './queue-factory'; } from './queue-factory';
// Re-export types for convenience // DLQ handling
export { DLQHandler } from './dlq-handler';
// Metrics
export { QueueMetricsCollector } from './queue-metrics';
// Rate limiting
export { QueueRateLimiter } from './rate-limiter';
// Types
export type { export type {
// Core types
JobData,
JobOptions,
QueueOptions,
QueueStats,
GlobalStats,
// Batch processing types
BatchResult, BatchResult,
JobHandler,
ProcessOptions, ProcessOptions,
BatchJobData,
// Handler types
JobHandler,
HandlerConfig, HandlerConfig,
HandlerConfigWithSchedule, HandlerConfigWithSchedule,
HandlerInitializer, HandlerInitializer,
// Configuration types
RedisConfig,
QueueConfig, QueueConfig,
ScheduledJob, QueueManagerConfig,
// Rate limiting types
RateLimitConfig, RateLimitConfig,
RateLimitRule, RateLimitRule,
// DLQ types
DLQConfig, DLQConfig,
DLQJobInfo,
// Scheduled job types
ScheduledJob,
ScheduleConfig,
} from './types'; } from './types';

View file

@ -2,7 +2,7 @@ import { getLogger } from '@stock-bot/logger';
import { QueueManager } from './queue-manager'; import { QueueManager } from './queue-manager';
import { Queue } from './queue'; import { Queue } from './queue';
import { processItems } from './batch-processor'; import { processItems } from './batch-processor';
import type { ProcessOptions, BatchResult, QueueManagerConfig } from './types'; import type { ProcessOptions, BatchResult, QueueManagerConfig, RedisConfig, JobOptions } from './types';
const logger = getLogger('queue-factory'); const logger = getLogger('queue-factory');
@ -11,8 +11,8 @@ const logger = getLogger('queue-factory');
* This now uses the singleton QueueManager pattern * This now uses the singleton QueueManager pattern
*/ */
export async function initializeQueueSystem(config: { export async function initializeQueueSystem(config: {
redis: any; redis: RedisConfig;
defaultJobOptions?: any; defaultJobOptions?: JobOptions;
workers?: number; workers?: number;
concurrency?: number; concurrency?: number;
}): Promise<void> { }): Promise<void> {

View file

@ -1,13 +1,14 @@
import { getLogger } from '@stock-bot/logger'; import { getLogger } from '@stock-bot/logger';
import { QueueRateLimiter } from './rate-limiter'; import { QueueRateLimiter } from './rate-limiter';
import { Queue, type QueueConfig } from './queue'; import { Queue, type QueueWorkerConfig } from './queue';
import { CacheProvider, createCache } from '@stock-bot/cache'; import { CacheProvider, createCache } from '@stock-bot/cache';
import type { import type {
QueueManagerConfig, QueueManagerConfig,
QueueOptions, QueueOptions,
GlobalStats, GlobalStats,
QueueStats, QueueStats,
RateLimitRule RateLimitRule,
RedisConfig
} from './types'; } from './types';
import { getRedisConnection } from './utils'; import { getRedisConnection } from './utils';
@ -22,7 +23,7 @@ export class QueueManager {
private queues = new Map<string, Queue>(); private queues = new Map<string, Queue>();
private caches = new Map<string, CacheProvider>(); private caches = new Map<string, CacheProvider>();
private rateLimiter?: QueueRateLimiter; private rateLimiter?: QueueRateLimiter;
private redisConnection: any; private redisConnection: ReturnType<typeof getRedisConnection>;
private isShuttingDown = false; private isShuttingDown = false;
private isInitialized = false; private isInitialized = false;
@ -93,7 +94,7 @@ export class QueueManager {
}; };
// Prepare queue configuration // Prepare queue configuration
const queueConfig: QueueConfig = { const queueConfig: QueueWorkerConfig = {
workers: mergedOptions.workers, workers: mergedOptions.workers,
concurrency: mergedOptions.concurrency, concurrency: mergedOptions.concurrency,
startWorker: mergedOptions.workers && mergedOptions.workers > 0, startWorker: mergedOptions.workers && mergedOptions.workers > 0,

View file

@ -1,12 +1,12 @@
import { Queue as BullQueue, Worker, QueueEvents, type Job } from 'bullmq'; import { Queue as BullQueue, Worker, QueueEvents, type Job } from 'bullmq';
import { getLogger } from '@stock-bot/logger'; import { getLogger } from '@stock-bot/logger';
import { handlerRegistry } from './handler-registry'; import { handlerRegistry } from './handler-registry';
import type { JobData, JobOptions, QueueStats } from './types'; import type { JobData, JobOptions, QueueStats, RedisConfig } from './types';
import { getRedisConnection } from './utils'; import { getRedisConnection } from './utils';
const logger = getLogger('queue'); const logger = getLogger('queue');
export interface QueueConfig { export interface QueueWorkerConfig {
workers?: number; workers?: number;
concurrency?: number; concurrency?: number;
startWorker?: boolean; startWorker?: boolean;
@ -21,13 +21,13 @@ export class Queue {
private workers: Worker[] = []; private workers: Worker[] = [];
private queueEvents?: QueueEvents; private queueEvents?: QueueEvents;
private queueName: string; private queueName: string;
private redisConfig: any; private redisConfig: RedisConfig;
constructor( constructor(
queueName: string, queueName: string,
redisConfig: any, redisConfig: RedisConfig,
defaultJobOptions: JobOptions = {}, defaultJobOptions: JobOptions = {},
config: QueueConfig = {} config: QueueWorkerConfig = {}
) { ) {
this.queueName = queueName; this.queueName = queueName;
this.redisConfig = redisConfig; this.redisConfig = redisConfig;

View file

@ -1,28 +1,19 @@
import { RateLimiterRedis, RateLimiterRes } from 'rate-limiter-flexible'; import { RateLimiterRedis, RateLimiterRes } from 'rate-limiter-flexible';
import { getLogger } from '@stock-bot/logger'; import { getLogger } from '@stock-bot/logger';
import type { RateLimitConfig as BaseRateLimitConfig, RateLimitRule } from './types';
const logger = getLogger('rate-limiter'); const logger = getLogger('rate-limiter');
export interface RateLimitConfig { // Extend the base config to add rate-limiter specific fields
points: number; // Number of requests export interface RateLimitConfig extends BaseRateLimitConfig {
duration: number; // Per duration in seconds
blockDuration?: number; // Block duration in seconds
keyPrefix?: string; keyPrefix?: string;
} }
export interface RateLimitRule {
level: 'global' | 'queue' | 'handler' | 'operation';
queueName?: string; // For queue-level limits
handler?: string; // For handler-level limits
operation?: string; // For operation-level limits (most specific)
config: RateLimitConfig;
}
export class QueueRateLimiter { export class QueueRateLimiter {
private limiters = new Map<string, RateLimiterRedis>(); private limiters = new Map<string, RateLimiterRedis>();
private rules: RateLimitRule[] = []; private rules: RateLimitRule[] = [];
constructor(private redisClient: any) {} constructor(private redisClient: ReturnType<typeof import('./utils').getRedisConnection>) {}
/** /**
* Add a rate limit rule * Add a rate limit rule

View file

@ -1,9 +1,9 @@
// Types for queue operations // Types for queue operations
export interface JobData { export interface JobData<T = unknown> {
type?: string; type?: string;
handler: string; handler: string;
operation: string; operation: string;
payload: any; payload: T;
priority?: number; priority?: number;
} }
@ -19,8 +19,6 @@ export interface ProcessOptions {
// Job routing information // Job routing information
handler?: string; handler?: string;
operation?: string; operation?: string;
// Optional queue for overloaded function signatures
queue?: any; // QueueManager reference
} }
export interface BatchResult { export interface BatchResult {
@ -33,8 +31,8 @@ export interface BatchResult {
// New improved types for the refactored architecture // New improved types for the refactored architecture
export interface RedisConfig { export interface RedisConfig {
host?: string; host: string;
port?: number; port: number;
password?: string; password?: string;
db?: number; db?: number;
} }
@ -96,14 +94,14 @@ export interface QueueConfig extends QueueManagerConfig {
enableMetrics?: boolean; enableMetrics?: boolean;
} }
export interface JobHandler { export interface JobHandler<TPayload = unknown, TResult = unknown> {
(payload: any): Promise<any>; (payload: TPayload): Promise<TResult>;
} }
export interface ScheduledJob { export interface ScheduledJob<T = unknown> {
type: string; type: string;
operation: string; operation: string;
payload: any; payload: T;
cronPattern: string; cronPattern: string;
priority?: number; priority?: number;
description?: string; description?: string;

View file

@ -1,12 +1,9 @@
import type { RedisConfig } from './types';
/** /**
* Get Redis connection configuration with retry settings * Get Redis connection configuration with retry settings
*/ */
export function getRedisConnection(config: { export function getRedisConnection(config: RedisConfig) {
host: string;
port: number;
password?: string;
db?: number;
}) {
const isTest = process.env.NODE_ENV === 'test' || process.env.BUNIT === '1'; const isTest = process.env.NODE_ENV === 'test' || process.env.BUNIT === '1';
return { return {