firestore-queue
Version:
A powerful, scalable queue system built on Google Firestore with time-based indexing, auto-configuration, and connection reuse
89 lines • 4.43 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.QueueConfigSchema = exports.ConsumerStateSchema = exports.QueueDocumentSchema = exports.QueueMessageSchema = void 0;
const zod_1 = require("zod");
/**
* Core queue message schema with Zod validation
*/
exports.QueueMessageSchema = zod_1.z.object({
id: zod_1.z.string().optional(), // Auto-generated if not provided
type: zod_1.z.string(), // Message type for routing
payload: zod_1.z.any(), // Message data
priority: zod_1.z.number().min(1).max(10).default(5), // 1=highest, 10=lowest
retryable: zod_1.z.boolean().default(true),
maxRetries: zod_1.z.number().min(0).default(3),
retryCount: zod_1.z.number().min(0).default(0),
ttlSeconds: zod_1.z.number().positive().optional(), // Message-specific TTL
version: zod_1.z.number().min(1).default(1), // For updatable messages
scheduledFor: zod_1.z.date().optional(), // Delayed execution
tags: zod_1.z.array(zod_1.z.string()).default([]), // For filtering/routing
metadata: zod_1.z.record(zod_1.z.any()).default({}), // Additional context
});
/**
* Internal queue document schema (what's stored in Firestore)
*/
exports.QueueDocumentSchema = exports.QueueMessageSchema.extend({
id: zod_1.z.string(), // Required in Firestore
status: zod_1.z.enum(['pending', 'processing', 'completed', 'failed', 'expired']).default('pending'),
createdAt: zod_1.z.custom(), // Firestore timestamp
updatedAt: zod_1.z.custom(), // For time-based indexing
expiresAt: zod_1.z.custom().optional(), // TTL timestamp
processingStartedAt: zod_1.z.custom().optional(),
completedAt: zod_1.z.custom().optional(),
error: zod_1.z.string().optional(),
lockedBy: zod_1.z.string().optional(), // Consumer ID for processing lock
lockedUntil: zod_1.z.custom().optional(), // Lock expiration
});
/**
* Consumer tracking schema
*/
exports.ConsumerStateSchema = zod_1.z.object({
consumerId: zod_1.z.string(),
queueName: zod_1.z.string(),
lastProcessedTimestamp: zod_1.z.custom(), // Resume point
isActive: zod_1.z.boolean().default(true),
heartbeatAt: zod_1.z.custom(), // Health check
processedCount: zod_1.z.number().min(0).default(0),
errorCount: zod_1.z.number().min(0).default(0),
lastError: zod_1.z.string().optional(),
configuration: zod_1.z.object({
batchSize: zod_1.z.number().min(1).max(1000).default(50),
pollIntervalMs: zod_1.z.number().min(100).default(5000),
lockTimeoutMs: zod_1.z.number().min(1000).default(300000), // 5 minutes
maxConcurrency: zod_1.z.number().min(1).default(1),
}).default({}),
});
/**
* Queue configuration schema
*/
exports.QueueConfigSchema = zod_1.z.object({
projectId: zod_1.z.string(),
databaseId: zod_1.z.string().default('(default)'),
queueCollection: zod_1.z.string().default('fire_queue'),
consumerCollection: zod_1.z.string().default('fire_queue_consumers'),
// Global defaults
defaultTtlSeconds: zod_1.z.number().positive().default(86400), // 24 hours
defaultBatchSize: zod_1.z.number().min(1).max(1000).default(50),
defaultPollIntervalMs: zod_1.z.number().min(100).default(5000),
// Cleanup configuration
enableAutoCleanup: zod_1.z.boolean().default(true),
cleanupIntervalMs: zod_1.z.number().min(60000).default(300000), // 5 minutes
retainCompletedSeconds: zod_1.z.number().min(0).default(86400), // 24 hours
// Index optimization
enableTimeBasedSharding: zod_1.z.boolean().default(false),
shardIntervalHours: zod_1.z.number().min(1).max(168).default(24), // 1 day
autoCreateIndexes: zod_1.z.boolean().default(true), // Auto-create Firestore indexes
// Firebase configuration
serviceAccountPath: zod_1.z.string().optional(),
firestoreInstance: zod_1.z.any().optional(), // Pre-configured Firestore instance
// Consumer configurations
consumers: zod_1.z.record(zod_1.z.object({
enabled: zod_1.z.boolean().default(true),
batchSize: zod_1.z.number().min(1).max(1000).optional(),
pollIntervalMs: zod_1.z.number().min(100).optional(),
maxConcurrency: zod_1.z.number().min(1).default(1),
messageTypes: zod_1.z.array(zod_1.z.string()).optional(), // Filter by message types
tags: zod_1.z.array(zod_1.z.string()).optional(), // Filter by tags
})).default({}),
});
//# sourceMappingURL=index.js.map