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.

194 lines (193 loc) 6.75 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.TaskController = void 0; /** * Task controller for handling HTTP requests from Google Cloud Tasks */ class TaskController { constructor(cloudTaskMQ) { this.cloudTaskMQ = cloudTaskMQ; } /** * Handle task processing requests from Google Cloud Tasks */ async processTask(req, res) { try { // Validate request if (!req.body) { res.status(400).json({ error: 'Request body is required' }); return; } const { taskId, queueName, data, attempts, maxAttempts, chain, uniquenessKey } = req.body; // Basic validation if (!taskId || !queueName) { res.status(400).json({ error: 'taskId and queueName are required' }); return; } // Optional: Validate Cloud Tasks headers for security const cloudTasksTaskName = req.headers['x-cloudtasks-taskname']; const cloudTasksQueueName = req.headers['x-cloudtasks-queuename']; if (process.env.NODE_ENV === 'production') { if (!cloudTasksTaskName || !cloudTasksQueueName) { res.status(401).json({ error: 'Invalid Cloud Tasks request' }); return; } } // Process the task const result = await this.cloudTaskMQ.processTask({ taskId, queueName, data, attempts: attempts || 0, maxAttempts: maxAttempts || 3, chain, uniquenessKey, }); res.status(200).json({ success: true, taskId, result, }); } catch (error) { console.error('Error processing task:', error); // Return appropriate status code const statusCode = error instanceof Error && error.message.includes('not found') ? 404 : 500; res.status(statusCode).json({ success: false, error: error instanceof Error ? error.message : 'Unknown error', }); } } /** * Handle task progress updates */ async updateProgress(req, res) { try { const { taskId } = req.params; const { percentage, data } = req.body; if (!taskId) { res.status(400).json({ error: 'taskId is required' }); return; } if (percentage === undefined || percentage < 0 || percentage > 100) { res.status(400).json({ error: 'Valid percentage (0-100) is required' }); return; } await this.cloudTaskMQ.updateTaskProgress(taskId, { percentage, data }); res.status(200).json({ success: true, taskId, progress: { percentage, data }, }); } catch (error) { console.error('Error updating task progress:', error); const statusCode = error instanceof Error && error.message.includes('not found') ? 404 : 500; res.status(statusCode).json({ success: false, error: error instanceof Error ? error.message : 'Unknown error', }); } } /** * Get task information */ async getTask(req, res) { try { const { taskId } = req.params; if (!taskId) { res.status(400).json({ error: 'taskId is required' }); return; } const task = await this.cloudTaskMQ.getTask(taskId); if (!task) { res.status(404).json({ error: 'Task not found' }); return; } res.status(200).json({ success: true, task, }); } catch (error) { console.error('Error getting task:', error); res.status(500).json({ success: false, error: error instanceof Error ? error.message : 'Unknown error', }); } } /** * List tasks with filtering */ async listTasks(req, res) { try { const { status, queueName, chainId, uniquenessKey, limit = 50, offset = 0, sortField = 'createdAt', sortOrder = 'desc', } = req.query; const options = { limit: Math.min(parseInt(limit) || 50, 100), // Max 100 offset: parseInt(offset) || 0, sort: { field: sortField, order: sortOrder, }, }; if (status) { options.status = Array.isArray(status) ? status : [status]; } if (queueName) { options.queueName = queueName; } if (chainId) { options.chainId = chainId; } if (uniquenessKey) { options.uniquenessKey = uniquenessKey; } const [tasks, total] = await Promise.all([ this.cloudTaskMQ.getTasks(options), this.cloudTaskMQ.getTaskCount(options), ]); res.status(200).json({ success: true, tasks, pagination: { total, limit: options.limit, offset: options.offset, hasMore: (options.offset || 0) + (options.limit || 0) < total, }, }); } catch (error) { console.error('Error listing tasks:', error); res.status(500).json({ success: false, error: error instanceof Error ? error.message : 'Unknown error', }); } } /** * Health check endpoint */ async healthCheck(req, res) { try { const isInitialized = this.cloudTaskMQ.isInitialized(); res.status(isInitialized ? 200 : 503).json({ status: isInitialized ? 'healthy' : 'unhealthy', initialized: isInitialized, timestamp: new Date().toISOString(), }); } catch (error) { res.status(503).json({ status: 'unhealthy', error: error instanceof Error ? error.message : 'Unknown error', timestamp: new Date().toISOString(), }); } } } exports.TaskController = TaskController;