@clipwhisperer/common
Version:
ClipWhisperer Common - Shared library providing core utilities, database schemas, authentication, bucket management, and common functionality across all ClipWhisperer microservices
178 lines (160 loc) • 4.72 kB
text/typescript
/**
* Queue Infrastructure
* Centralized BullMQ queue and worker management
*/
import { Queue, Worker, Job } from "bullmq";
import { REDIS_CONNECTION_CONFIG, DEFAULT_QUEUE_OPTIONS, QUEUE_NAMES } from "../constants/redis";
import { PerformanceTracker } from "./performance";
export type QueueJobInput = Record<string, any>;
export type QueueJobOutput = Record<string, any>;
export interface QueueConfig {
name: string;
connection?: {
host: string;
port: number;
};
defaultJobOptions?: {
removeOnComplete?: boolean;
removeOnFail?: boolean;
attempts?: number;
backoff?: {
type: string;
delay: number;
};
};
}
/**
* Queue Factory - Creates standardized BullMQ queues
*/
export class QueueFactory {
/**
* Create a queue with standard configuration
*/
static createQueue<TInput extends QueueJobInput, TOutput extends QueueJobOutput>(
queueName: string,
config?: Partial<QueueConfig>
): Queue<TInput, TOutput> {
return new Queue<TInput, TOutput>(queueName, {
connection: config?.connection || REDIS_CONNECTION_CONFIG,
defaultJobOptions: {
...DEFAULT_QUEUE_OPTIONS,
...config?.defaultJobOptions,
},
});
}
/**
* Create a worker with standard configuration
*/
static createWorker<TInput extends QueueJobInput, TOutput extends QueueJobOutput>(
queueName: string,
processor: (job: Job<TInput, TOutput>) => Promise<TOutput>,
config?: Partial<QueueConfig>
): Worker<TInput, TOutput> {
return new Worker<TInput, TOutput>(
queueName,
processor,
{
connection: config?.connection || REDIS_CONNECTION_CONFIG,
...config,
}
);
}
}
/**
* Base Queue Manager - Provides common queue operations
*/
export abstract class BaseQueueManager<TInput extends QueueJobInput, TOutput extends QueueJobOutput> {
protected queue: Queue<TInput, TOutput>;
protected worker?: Worker<TInput, TOutput>;
protected performanceTracker: PerformanceTracker;
constructor(
protected queueName: string,
protected config?: Partial<QueueConfig>
) {
this.queue = QueueFactory.createQueue<TInput, TOutput>(queueName, config);
this.performanceTracker = new PerformanceTracker();
}
/**
* Add a job to the queue
*/
async addJob(
jobName: string,
data: TInput,
options?: {
removeOnComplete?: boolean;
removeOnFail?: boolean;
delay?: number;
attempts?: number;
}
): Promise<{ jobId: string }> {
const startTime = Date.now();
try {
const job = await (this.queue as any).add(jobName, data, {
...DEFAULT_QUEUE_OPTIONS,
...options,
});
this.performanceTracker.trackSuccess(Date.now() - startTime);
return { jobId: job.id || `job_${Date.now()}` };
} catch (error) {
this.performanceTracker.trackError(Date.now() - startTime);
throw error;
}
}
/**
* Start the worker
*/
startWorker(processor: (job: Job<TInput, TOutput>) => Promise<TOutput>): void {
this.worker = QueueFactory.createWorker<TInput, TOutput>(
this.queueName,
async (job) => {
return await this.performanceTracker.trackRequest(async () => {
return await processor(job);
});
},
this.config
);
this.worker.on("completed", (job) => {
console.log(`✅ Job ${job.id} completed successfully`);
});
this.worker.on("failed", (job, err) => {
console.error(`❌ Job ${job?.id} failed:`, err);
});
}
/**
* Get queue statistics
*/
async getQueueStats(): Promise<{
waiting: number;
active: number;
completed: number;
failed: number;
}> {
return {
waiting: await this.queue.getWaiting().then(jobs => jobs.length),
active: await this.queue.getActive().then(jobs => jobs.length),
completed: await this.queue.getCompleted().then(jobs => jobs.length),
failed: await this.queue.getFailed().then(jobs => jobs.length),
};
}
/**
* Get enhanced performance metrics including queue size
*/
async getPerformanceMetrics() {
const baseMetrics = this.performanceTracker.getMetrics();
const queueStats = await this.getQueueStats();
return {
...baseMetrics,
queueSize: queueStats.waiting + queueStats.active,
queueStats,
};
}
/**
* Close queue and worker connections
*/
async close(): Promise<void> {
await this.queue.close();
if (this.worker) {
await this.worker.close();
}
}
}