firestore-queue
Version:
A powerful, scalable queue system built on Google Firestore with time-based indexing, auto-configuration, and connection reuse
354 lines • 12.5 kB
TypeScript
import { z } from 'zod';
import { Timestamp } from 'firebase-admin/firestore';
/**
* Core queue message schema with Zod validation
*/
export declare const QueueMessageSchema: z.ZodObject<{
id: z.ZodOptional<z.ZodString>;
type: z.ZodString;
payload: z.ZodAny;
priority: z.ZodDefault<z.ZodNumber>;
retryable: z.ZodDefault<z.ZodBoolean>;
maxRetries: z.ZodDefault<z.ZodNumber>;
retryCount: z.ZodDefault<z.ZodNumber>;
ttlSeconds: z.ZodOptional<z.ZodNumber>;
version: z.ZodDefault<z.ZodNumber>;
scheduledFor: z.ZodOptional<z.ZodDate>;
tags: z.ZodDefault<z.ZodArray<z.ZodString, "many">>;
metadata: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodAny>>;
}, "strip", z.ZodTypeAny, {
type: string;
priority: number;
retryable: boolean;
maxRetries: number;
retryCount: number;
version: number;
tags: string[];
metadata: Record<string, any>;
id?: string | undefined;
payload?: any;
ttlSeconds?: number | undefined;
scheduledFor?: Date | undefined;
}, {
type: string;
id?: string | undefined;
payload?: any;
priority?: number | undefined;
retryable?: boolean | undefined;
maxRetries?: number | undefined;
retryCount?: number | undefined;
ttlSeconds?: number | undefined;
version?: number | undefined;
scheduledFor?: Date | undefined;
tags?: string[] | undefined;
metadata?: Record<string, any> | undefined;
}>;
export type QueueMessage = z.infer<typeof QueueMessageSchema>;
/**
* Input type for creating queue messages - optional properties with defaults
*/
export type QueueMessageInput = {
id?: string;
type: string;
payload?: any;
priority?: number;
retryable?: boolean;
maxRetries?: number;
retryCount?: number;
ttlSeconds?: number;
version?: number;
scheduledFor?: Date;
tags?: string[];
metadata?: Record<string, any>;
};
/**
* Internal queue document schema (what's stored in Firestore)
*/
export declare const QueueDocumentSchema: z.ZodObject<{
type: z.ZodString;
payload: z.ZodAny;
priority: z.ZodDefault<z.ZodNumber>;
retryable: z.ZodDefault<z.ZodBoolean>;
maxRetries: z.ZodDefault<z.ZodNumber>;
retryCount: z.ZodDefault<z.ZodNumber>;
ttlSeconds: z.ZodOptional<z.ZodNumber>;
version: z.ZodDefault<z.ZodNumber>;
scheduledFor: z.ZodOptional<z.ZodDate>;
tags: z.ZodDefault<z.ZodArray<z.ZodString, "many">>;
metadata: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodAny>>;
} & {
id: z.ZodString;
status: z.ZodDefault<z.ZodEnum<["pending", "processing", "completed", "failed", "expired"]>>;
createdAt: z.ZodType<Timestamp, z.ZodTypeDef, Timestamp>;
updatedAt: z.ZodType<Timestamp, z.ZodTypeDef, Timestamp>;
expiresAt: z.ZodOptional<z.ZodType<Timestamp, z.ZodTypeDef, Timestamp>>;
processingStartedAt: z.ZodOptional<z.ZodType<Timestamp, z.ZodTypeDef, Timestamp>>;
completedAt: z.ZodOptional<z.ZodType<Timestamp, z.ZodTypeDef, Timestamp>>;
error: z.ZodOptional<z.ZodString>;
lockedBy: z.ZodOptional<z.ZodString>;
lockedUntil: z.ZodOptional<z.ZodType<Timestamp, z.ZodTypeDef, Timestamp>>;
}, "strip", z.ZodTypeAny, {
id: string;
type: string;
priority: number;
retryable: boolean;
maxRetries: number;
retryCount: number;
version: number;
status: "pending" | "processing" | "completed" | "failed" | "expired";
tags: string[];
metadata: Record<string, any>;
createdAt: Timestamp;
updatedAt: Timestamp;
payload?: any;
ttlSeconds?: number | undefined;
scheduledFor?: Date | undefined;
expiresAt?: Timestamp | undefined;
processingStartedAt?: Timestamp | undefined;
completedAt?: Timestamp | undefined;
error?: string | undefined;
lockedBy?: string | undefined;
lockedUntil?: Timestamp | undefined;
}, {
id: string;
type: string;
createdAt: Timestamp;
updatedAt: Timestamp;
payload?: any;
priority?: number | undefined;
retryable?: boolean | undefined;
maxRetries?: number | undefined;
retryCount?: number | undefined;
ttlSeconds?: number | undefined;
version?: number | undefined;
scheduledFor?: Date | undefined;
status?: "pending" | "processing" | "completed" | "failed" | "expired" | undefined;
tags?: string[] | undefined;
metadata?: Record<string, any> | undefined;
expiresAt?: Timestamp | undefined;
processingStartedAt?: Timestamp | undefined;
completedAt?: Timestamp | undefined;
error?: string | undefined;
lockedBy?: string | undefined;
lockedUntil?: Timestamp | undefined;
}>;
export type QueueDocument = z.infer<typeof QueueDocumentSchema>;
/**
* Consumer tracking schema
*/
export declare const ConsumerStateSchema: z.ZodObject<{
consumerId: z.ZodString;
queueName: z.ZodString;
lastProcessedTimestamp: z.ZodType<Timestamp, z.ZodTypeDef, Timestamp>;
isActive: z.ZodDefault<z.ZodBoolean>;
heartbeatAt: z.ZodType<Timestamp, z.ZodTypeDef, Timestamp>;
processedCount: z.ZodDefault<z.ZodNumber>;
errorCount: z.ZodDefault<z.ZodNumber>;
lastError: z.ZodOptional<z.ZodString>;
configuration: z.ZodDefault<z.ZodObject<{
batchSize: z.ZodDefault<z.ZodNumber>;
pollIntervalMs: z.ZodDefault<z.ZodNumber>;
lockTimeoutMs: z.ZodDefault<z.ZodNumber>;
maxConcurrency: z.ZodDefault<z.ZodNumber>;
}, "strip", z.ZodTypeAny, {
batchSize: number;
pollIntervalMs: number;
lockTimeoutMs: number;
maxConcurrency: number;
}, {
batchSize?: number | undefined;
pollIntervalMs?: number | undefined;
lockTimeoutMs?: number | undefined;
maxConcurrency?: number | undefined;
}>>;
}, "strip", z.ZodTypeAny, {
consumerId: string;
queueName: string;
lastProcessedTimestamp: Timestamp;
isActive: boolean;
heartbeatAt: Timestamp;
processedCount: number;
errorCount: number;
configuration: {
batchSize: number;
pollIntervalMs: number;
lockTimeoutMs: number;
maxConcurrency: number;
};
lastError?: string | undefined;
}, {
consumerId: string;
queueName: string;
lastProcessedTimestamp: Timestamp;
heartbeatAt: Timestamp;
isActive?: boolean | undefined;
processedCount?: number | undefined;
errorCount?: number | undefined;
lastError?: string | undefined;
configuration?: {
batchSize?: number | undefined;
pollIntervalMs?: number | undefined;
lockTimeoutMs?: number | undefined;
maxConcurrency?: number | undefined;
} | undefined;
}>;
export type ConsumerState = z.infer<typeof ConsumerStateSchema>;
/**
* Queue configuration schema
*/
export declare const QueueConfigSchema: z.ZodObject<{
projectId: z.ZodString;
databaseId: z.ZodDefault<z.ZodString>;
queueCollection: z.ZodDefault<z.ZodString>;
consumerCollection: z.ZodDefault<z.ZodString>;
defaultTtlSeconds: z.ZodDefault<z.ZodNumber>;
defaultBatchSize: z.ZodDefault<z.ZodNumber>;
defaultPollIntervalMs: z.ZodDefault<z.ZodNumber>;
enableAutoCleanup: z.ZodDefault<z.ZodBoolean>;
cleanupIntervalMs: z.ZodDefault<z.ZodNumber>;
retainCompletedSeconds: z.ZodDefault<z.ZodNumber>;
enableTimeBasedSharding: z.ZodDefault<z.ZodBoolean>;
shardIntervalHours: z.ZodDefault<z.ZodNumber>;
autoCreateIndexes: z.ZodDefault<z.ZodBoolean>;
serviceAccountPath: z.ZodOptional<z.ZodString>;
firestoreInstance: z.ZodOptional<z.ZodAny>;
consumers: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodObject<{
enabled: z.ZodDefault<z.ZodBoolean>;
batchSize: z.ZodOptional<z.ZodNumber>;
pollIntervalMs: z.ZodOptional<z.ZodNumber>;
maxConcurrency: z.ZodDefault<z.ZodNumber>;
messageTypes: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
tags: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
}, "strip", z.ZodTypeAny, {
maxConcurrency: number;
enabled: boolean;
tags?: string[] | undefined;
batchSize?: number | undefined;
pollIntervalMs?: number | undefined;
messageTypes?: string[] | undefined;
}, {
tags?: string[] | undefined;
batchSize?: number | undefined;
pollIntervalMs?: number | undefined;
maxConcurrency?: number | undefined;
enabled?: boolean | undefined;
messageTypes?: string[] | undefined;
}>>>;
}, "strip", z.ZodTypeAny, {
projectId: string;
databaseId: string;
queueCollection: string;
consumerCollection: string;
defaultTtlSeconds: number;
defaultBatchSize: number;
defaultPollIntervalMs: number;
enableAutoCleanup: boolean;
cleanupIntervalMs: number;
retainCompletedSeconds: number;
enableTimeBasedSharding: boolean;
shardIntervalHours: number;
autoCreateIndexes: boolean;
consumers: Record<string, {
maxConcurrency: number;
enabled: boolean;
tags?: string[] | undefined;
batchSize?: number | undefined;
pollIntervalMs?: number | undefined;
messageTypes?: string[] | undefined;
}>;
serviceAccountPath?: string | undefined;
firestoreInstance?: any;
}, {
projectId: string;
databaseId?: string | undefined;
queueCollection?: string | undefined;
consumerCollection?: string | undefined;
defaultTtlSeconds?: number | undefined;
defaultBatchSize?: number | undefined;
defaultPollIntervalMs?: number | undefined;
enableAutoCleanup?: boolean | undefined;
cleanupIntervalMs?: number | undefined;
retainCompletedSeconds?: number | undefined;
enableTimeBasedSharding?: boolean | undefined;
shardIntervalHours?: number | undefined;
autoCreateIndexes?: boolean | undefined;
serviceAccountPath?: string | undefined;
firestoreInstance?: any;
consumers?: Record<string, {
tags?: string[] | undefined;
batchSize?: number | undefined;
pollIntervalMs?: number | undefined;
maxConcurrency?: number | undefined;
enabled?: boolean | undefined;
messageTypes?: string[] | undefined;
}> | undefined;
}>;
export type QueueConfig = z.infer<typeof QueueConfigSchema>;
/**
* Batch processing result
*/
export interface BatchResult {
processed: number;
successful: number;
failed: number;
errors: Array<{
messageId: string;
error: string;
}>;
}
/**
* Queue metrics
*/
export interface QueueMetrics {
totalMessages: number;
pendingMessages: number;
processingMessages: number;
completedMessages: number;
failedMessages: number;
expiredMessages: number;
averageProcessingTimeMs: number;
messagesByType: Record<string, number>;
messagesByPriority: Record<number, number>;
consumerHealth: Array<{
consumerId: string;
isActive: boolean;
lastHeartbeat: Date;
processedCount: number;
errorCount: number;
}>;
}
/**
* Message handler function type
*/
export type MessageHandler<T = any> = (messages: Array<{
id: string;
type: string;
payload: T;
metadata: Record<string, any>;
ack: () => Promise<void>;
nack: (error?: string) => Promise<void>;
updatePayload: (newPayload: T) => Promise<void>;
}>) => Promise<void>;
/**
* Hook function types for extensibility
*/
export type BeforeEnqueueHook = (message: QueueMessage) => Promise<QueueMessage>;
export type AfterEnqueueHook = (message: QueueDocument) => Promise<void>;
export type BeforeProcessHook = (messages: QueueDocument[]) => Promise<QueueDocument[]>;
export type AfterProcessHook = (results: BatchResult) => Promise<void>;
/**
* Queue events for monitoring
*/
export interface QueueEvents {
'message.enqueued': (message: QueueDocument) => void;
'message.processing': (message: QueueDocument, consumerId: string) => void;
'message.completed': (message: QueueDocument, consumerId: string) => void;
'message.failed': (message: QueueDocument, error: string, consumerId: string) => void;
'message.expired': (message: QueueDocument) => void;
'message.updated': (oldMessage: QueueDocument, newMessage: QueueDocument) => void;
'consumer.started': (consumerId: string) => void;
'consumer.stopped': (consumerId: string) => void;
'consumer.error': (consumerId: string, error: string) => void;
'batch.processed': (consumerId: string, result: BatchResult) => void;
}
//# sourceMappingURL=index.d.ts.map