UNPKG

nodejs-cloud-taskmq

Version:

Node.js TypeScript library for integrating Google Cloud Tasks with MongoDB/Redis/Memory/Custom for a BullMQ-like queue system. Compatible with NestJS but framework-agnostic.

238 lines (237 loc) 8.08 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.CloudTaskMQ = void 0; const producer_service_1 = require("./services/producer.service"); const consumer_service_1 = require("./services/consumer.service"); const rate_limiter_service_1 = require("./services/rate-limiter.service"); const memory_storage_adapter_1 = require("./adapters/memory-storage.adapter"); const redis_storage_adapter_1 = require("./adapters/redis-storage.adapter"); const mongo_storage_adapter_1 = require("./adapters/mongo-storage.adapter"); const events_1 = require("events"); /** * Main CloudTaskMQ class */ class CloudTaskMQ extends events_1.EventEmitter { constructor(config) { super(); this.config = config; this.initialized = false; this.storageAdapter = this.createStorageAdapter(); this.producerService = new producer_service_1.ProducerService(config, this.storageAdapter); this.consumerService = new consumer_service_1.ConsumerService(config, this.storageAdapter); this.rateLimiterService = new rate_limiter_service_1.RateLimiterService(this.storageAdapter); // Forward events this.producerService.on('taskAdded', (event) => this.emit('taskAdded', event)); this.consumerService.on('taskActive', (event) => this.emit('taskActive', event)); this.consumerService.on('taskCompleted', (event) => this.emit('taskCompleted', event)); this.consumerService.on('taskFailed', (event) => this.emit('taskFailed', event)); this.consumerService.on('taskProgress', (event) => this.emit('taskProgress', event)); } /** * Initialize CloudTaskMQ */ async initialize() { if (this.initialized) { return; } try { await this.storageAdapter.initialize(); await this.producerService.initialize(); await this.consumerService.initialize(); this.initialized = true; this.emit('initialized'); } catch (error) { this.emit('error', error); throw error; } } /** * Get producer service */ getProducer() { return this.producerService; } /** * Get consumer service */ getConsumer() { return this.consumerService; } /** * Get rate limiter service */ getRateLimiter() { return this.rateLimiterService; } /** * Get storage adapter */ getStorageAdapter() { return this.storageAdapter; } /** * Register a processor */ registerProcessor(processor) { if (!this.initialized) { throw new Error('CloudTaskMQ must be initialized before registering processors'); } this.consumerService.registerProcessor(processor); } /** * Process a task (called by HTTP endpoints) */ async processTask(payload) { if (!this.initialized) { throw new Error('CloudTaskMQ must be initialized before processing tasks'); } return await this.consumerService.processTask(payload); } /** * Add a task to a queue */ async addTask(queueName, data, options) { if (!this.initialized) { throw new Error('CloudTaskMQ must be initialized before adding tasks'); } return await this.producerService.addTask(queueName, data, options); } /** * Add a chain of tasks */ async addChain(queueName, tasks, chainOptions) { if (!this.initialized) { throw new Error('CloudTaskMQ must be initialized before adding task chains'); } return await this.producerService.addChain(queueName, tasks, chainOptions); } /** * Get task by ID */ async getTask(taskId) { if (!this.initialized) { throw new Error('CloudTaskMQ must be initialized before getting tasks'); } return await this.storageAdapter.getTask(taskId); } /** * Get tasks with filtering options */ async getTasks(options) { if (!this.initialized) { throw new Error('CloudTaskMQ must be initialized before getting tasks'); } return await this.storageAdapter.getTasks(options); } /** * Get task count */ async getTaskCount(options) { if (!this.initialized) { throw new Error('CloudTaskMQ must be initialized before getting task count'); } return await this.storageAdapter.getTaskCount(options); } /** * Update task progress */ async updateTaskProgress(taskId, progress) { if (!this.initialized) { throw new Error('CloudTaskMQ must be initialized before updating task progress'); } return await this.consumerService.updateTaskProgress(taskId, progress); } /** * Clean up old tasks */ async cleanup(options) { if (!this.initialized) { throw new Error('CloudTaskMQ must be initialized before cleanup'); } return await this.storageAdapter.cleanup(options); } /** * Check rate limit */ async checkRateLimit(key, options) { if (!this.initialized) { throw new Error('CloudTaskMQ must be initialized before checking rate limits'); } return await this.rateLimiterService.checkRateLimit(key, options); } /** * Get configuration */ getConfig() { return { ...this.config }; } /** * Check if initialized */ isInitialized() { return this.initialized; } /** * Close CloudTaskMQ and clean up resources */ async close() { if (!this.initialized) return; try { await this.producerService.close(); await this.consumerService.close(); await this.storageAdapter.close(); this.initialized = false; this.removeAllListeners(); this.emit('closed'); } catch (error) { // Try to clean up what we can even if some parts fail this.initialized = false; this.removeAllListeners(); // Only throw if it's not a connection-related error during shutdown if (error instanceof Error && !error.message.includes('Connection is closed')) { this.emit('error', error); throw error; } } } /** * Create storage adapter based on configuration */ createStorageAdapter() { const { storageAdapter, storageOptions = {} } = this.config; switch (storageAdapter) { case 'memory': return new memory_storage_adapter_1.MemoryStorageAdapter(); case 'redis': if (!storageOptions.redis) { throw new Error('Redis storage options are required when using Redis adapter'); } return new redis_storage_adapter_1.RedisStorageAdapter(storageOptions.redis); case 'mongo': if (!storageOptions.mongo) { throw new Error('MongoDB storage options are required when using MongoDB adapter'); } return new mongo_storage_adapter_1.MongoStorageAdapter(storageOptions.mongo); case 'custom': if (!storageOptions.customAdapter) { throw new Error('Custom storage adapter instance is required when using custom adapter'); } return storageOptions.customAdapter; default: throw new Error(`Unsupported storage adapter: ${storageAdapter}`); } } /** * Create CloudTaskMQ instance with async configuration */ static async create(configFactory) { const config = await configFactory(); const instance = new CloudTaskMQ(config); await instance.initialize(); return instance; } } exports.CloudTaskMQ = CloudTaskMQ;