@nicnocquee/dataqueue 1.20.0 → 1.22.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/types.ts","../src/log-context.ts","../src/queue.ts","../src/processor.ts","../src/db-util.ts","../src/index.ts"],"names":["JobEventType","FailureReason","AsyncLocalStorage","error","parse","Pool"],"mappings":"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","file":"index.cjs","sourcesContent":["import { Pool } from 'pg';\n\n// Utility type for job type keys\nexport type JobType<PayloadMap> = keyof PayloadMap & string;\n\nexport interface JobOptions<PayloadMap, T extends JobType<PayloadMap>> {\n jobType: T;\n payload: PayloadMap[T];\n maxAttempts?: number;\n priority?: number;\n runAt?: Date | null;\n /**\n * Timeout for this job in milliseconds. If not set, uses the processor default or unlimited.\n */\n timeoutMs?: number;\n /**\n * Tags for this job. Used for grouping, searching, or batch operations.\n */\n tags?: string[];\n}\n\nexport enum JobEventType {\n Added = 'added',\n Processing = 'processing',\n Completed = 'completed',\n Failed = 'failed',\n Cancelled = 'cancelled',\n Retried = 'retried',\n}\n\nexport interface JobEvent {\n id: number;\n jobId: number;\n eventType: JobEventType;\n createdAt: Date;\n metadata: any;\n}\n\nexport enum FailureReason {\n Timeout = 'timeout',\n HandlerError = 'handler_error',\n NoHandler = 'no_handler',\n}\n\nexport type JobStatus =\n | 'pending'\n | 'processing'\n | 'completed'\n | 'failed'\n | 'cancelled';\n\nexport interface JobRecord<PayloadMap, T extends JobType<PayloadMap>> {\n id: number;\n jobType: T;\n payload: PayloadMap[T];\n status: JobStatus;\n createdAt: Date;\n updatedAt: Date;\n lockedAt: Date | null;\n lockedBy: string | null;\n attempts: number;\n maxAttempts: number;\n nextAttemptAt: Date | null;\n priority: number;\n runAt: Date;\n pendingReason?: string | null;\n errorHistory?: { message: string; timestamp: string }[];\n /**\n * Timeout for this job in milliseconds (null means no timeout).\n */\n timeoutMs?: number | null;\n /**\n * The reason for the last failure, if any.\n */\n failureReason?: FailureReason | null;\n /**\n * The time the job was completed, if completed.\n */\n completedAt: Date | null;\n /**\n * The time the job was first picked up for processing.\n */\n startedAt: Date | null;\n /**\n * The time the job was last retried.\n */\n lastRetriedAt: Date | null;\n /**\n * The time the job last failed.\n */\n lastFailedAt: Date | null;\n /**\n * The time the job was last cancelled.\n */\n lastCancelledAt: Date | null;\n /**\n * Tags for this job. Used for grouping, searching, or batch operations.\n */\n tags?: string[];\n}\n\nexport type JobHandler<PayloadMap, T extends keyof PayloadMap> = (\n payload: PayloadMap[T],\n signal: AbortSignal,\n) => Promise<void>;\n\nexport type JobHandlers<PayloadMap> = {\n [K in keyof PayloadMap]: JobHandler<PayloadMap, K>;\n};\n\nexport interface ProcessorOptions {\n workerId?: string;\n /**\n * The number of jobs to process at a time.\n * - If not provided, the processor will process 10 jobs at a time.\n * - In serverless functions, it's better to process less jobs at a time since serverless functions are charged by the second and have a timeout.\n */\n batchSize?: number;\n /**\n * The maximum number of jobs to process in parallel per batch.\n * - If not provided, all jobs in the batch are processed in parallel.\n * - Set to 1 to process jobs sequentially.\n * - Set to a lower value to avoid resource exhaustion.\n */\n concurrency?: number;\n /**\n * The interval in milliseconds to poll for new jobs.\n * - If not provided, the processor will process jobs every 5 seconds when startInBackground is called.\n * - In serverless functions, it's better to leave this empty.\n * - If you call start instead of startInBackground, the pollInterval is ignored.\n */\n pollInterval?: number;\n onError?: (error: Error) => void;\n verbose?: boolean;\n /**\n * Only process jobs with this job type (string or array of strings). If omitted, all job types are processed.\n */\n jobType?: string | string[];\n}\n\nexport interface Processor {\n /**\n * Start the job processor in the background.\n * - This will run periodically (every pollInterval milliseconds or 5 seconds if not provided) and process jobs (as many as batchSize) as they become available.\n * - **You have to call the stop method to stop the processor.**\n * - Handlers are provided per-processor when calling createProcessor.\n * - In serverless functions, it's recommended to call start instead and await it to finish.\n */\n startInBackground: () => void;\n /**\n * Stop the job processor that runs in the background.\n */\n stop: () => void;\n /**\n * Check if the job processor is running.\n */\n isRunning: () => boolean;\n /**\n * Start the job processor synchronously.\n * - This will process jobs (as many as batchSize) immediately and then stop. The pollInterval is ignored.\n * - In serverless functions, it's recommended to use this instead of startInBackground.\n * - Returns the number of jobs processed.\n */\n start: () => Promise<number>;\n}\n\nexport interface JobQueueConfig {\n databaseConfig: {\n connectionString?: string;\n host?: string;\n port?: number;\n database?: string;\n user?: string;\n password?: string;\n ssl?: any;\n };\n verbose?: boolean;\n}\n\nexport type TagQueryMode = 'exact' | 'all' | 'any' | 'none';\n\nexport interface JobQueue<PayloadMap> {\n /**\n * Add a job to the job queue.\n */\n addJob: <T extends JobType<PayloadMap>>(\n job: JobOptions<PayloadMap, T>,\n ) => Promise<number>;\n /**\n * Get a job by its ID.\n */\n getJob: <T extends JobType<PayloadMap>>(\n id: number,\n ) => Promise<JobRecord<PayloadMap, T> | null>;\n /**\n * Get jobs by their status, with pagination.\n * - If no limit is provided, all jobs are returned.\n * - If no offset is provided, the first page is returned.\n * - The jobs are returned in descending order of createdAt.\n */\n getJobsByStatus: <T extends JobType<PayloadMap>>(\n status: JobStatus,\n limit?: number,\n offset?: number,\n ) => Promise<JobRecord<PayloadMap, T>[]>;\n /**\n * Get jobs by tag(s).\n * - Modes:\n * - 'exact': Jobs with exactly the same tags (no more, no less)\n * - 'all': Jobs that have all the given tags (can have more)\n * - 'any': Jobs that have at least one of the given tags\n * - 'none': Jobs that have none of the given tags\n * - Default mode is 'all'.\n */\n getJobsByTags: <T extends JobType<PayloadMap>>(\n tags: string[],\n mode?: TagQueryMode,\n limit?: number,\n offset?: number,\n ) => Promise<JobRecord<PayloadMap, T>[]>;\n /**\n * Get all jobs.\n */\n getAllJobs: <T extends JobType<PayloadMap>>(\n limit?: number,\n offset?: number,\n ) => Promise<JobRecord<PayloadMap, T>[]>;\n /**\n * Retry a job given its ID.\n * - This will set the job status back to 'pending', clear the locked_at and locked_by, and allow it to be picked up by other workers.\n */\n retryJob: (jobId: number) => Promise<void>;\n /**\n * Cleanup jobs that are older than the specified number of days.\n */\n cleanupOldJobs: (daysToKeep?: number) => Promise<number>;\n /**\n * Cancel a job given its ID.\n * - This will set the job status to 'cancelled' and clear the locked_at and locked_by.\n */\n cancelJob: (jobId: number) => Promise<void>;\n /**\n * Reclaim stuck jobs.\n * - If a process (e.g., API route or worker) crashes after marking a job as 'processing' but before completing it, the job can remain stuck in the 'processing' state indefinitely. This can happen if the process is killed or encounters an unhandled error after updating the job status but before marking it as 'completed' or 'failed'.\n * - This function will set the job status back to 'pending', clear the locked_at and locked_by, and allow it to be picked up by other workers.\n * - The default max processing time is 10 minutes.\n */\n reclaimStuckJobs: (maxProcessingTimeMinutes?: number) => Promise<number>;\n /**\n * Cancel all upcoming jobs that match the filters.\n * - If no filters are provided, all upcoming jobs are cancelled.\n * - If filters are provided, only jobs that match the filters are cancelled.\n * - The filters are:\n * - jobType: The job type to cancel.\n * - priority: The priority of the job to cancel.\n * - runAt: The time the job is scheduled to run at.\n * - tags: An object with 'values' (string[]) and 'mode' (TagQueryMode) for tag-based cancellation.\n */\n cancelAllUpcomingJobs: (filters?: {\n jobType?: string;\n priority?: number;\n runAt?: Date;\n tags?: { values: string[]; mode?: TagQueryMode };\n }) => Promise<number>;\n /**\n * Create a job processor. Handlers must be provided per-processor.\n */\n createProcessor: (\n handlers: JobHandlers<PayloadMap>,\n options?: ProcessorOptions,\n ) => Processor;\n\n /**\n * Get the job events for a job.\n */\n getJobEvents: (jobId: number) => Promise<JobEvent[]>;\n /**\n * Get the database pool.\n */\n getPool: () => Pool;\n}\n","import { AsyncLocalStorage } from 'async_hooks';\n\nexport const logStorage = new AsyncLocalStorage<{\n verbose: boolean;\n}>();\n\nexport const setLogContext = (verbose: boolean) => {\n logStorage.enterWith({ verbose });\n};\n\nexport const getLogContext = () => {\n return logStorage.getStore();\n};\n\nexport const log = (message: string) => {\n const context = getLogContext();\n if (context?.verbose) {\n console.log(message);\n }\n};\n","import { Pool } from 'pg';\nimport {\n JobOptions,\n JobRecord,\n FailureReason,\n JobEvent,\n JobEventType,\n TagQueryMode,\n} from './types.js';\nimport { log } from './log-context.js';\n\n/**\n * Record a job event in the job_events table\n */\nexport const recordJobEvent = async (\n pool: Pool,\n jobId: number,\n eventType: JobEventType,\n metadata?: any,\n): Promise<void> => {\n const client = await pool.connect();\n try {\n await client.query(\n `INSERT INTO job_events (job_id, event_type, metadata) VALUES ($1, $2, $3)`,\n [jobId, eventType, metadata ? JSON.stringify(metadata) : null],\n );\n } catch (error) {\n log(`Error recording job event for job ${jobId}: ${error}`);\n // Do not throw, to avoid interfering with main job logic\n } finally {\n client.release();\n }\n};\n\n/**\n * Add a job to the queue\n */\nexport const addJob = async <PayloadMap, T extends keyof PayloadMap & string>(\n pool: Pool,\n {\n jobType,\n payload,\n maxAttempts = 3,\n priority = 0,\n runAt = null,\n timeoutMs = undefined,\n tags = undefined,\n }: JobOptions<PayloadMap, T>,\n): Promise<number> => {\n const client = await pool.connect();\n try {\n let result;\n if (runAt) {\n result = await client.query(\n `INSERT INTO job_queue \n (job_type, payload, max_attempts, priority, run_at, timeout_ms, tags) \n VALUES ($1, $2, $3, $4, $5, $6, $7) \n RETURNING id`,\n [\n jobType,\n payload,\n maxAttempts,\n priority,\n runAt,\n timeoutMs ?? null,\n tags ?? null,\n ],\n );\n log(\n `Added job ${result.rows[0].id}: payload ${JSON.stringify(payload)}, runAt ${runAt.toISOString()}, priority ${priority}, maxAttempts ${maxAttempts} jobType ${jobType}, tags ${JSON.stringify(tags)}`,\n );\n } else {\n result = await client.query(\n `INSERT INTO job_queue \n (job_type, payload, max_attempts, priority, timeout_ms, tags) \n VALUES ($1, $2, $3, $4, $5, $6) \n RETURNING id`,\n [\n jobType,\n payload,\n maxAttempts,\n priority,\n timeoutMs ?? null,\n tags ?? null,\n ],\n );\n log(\n `Added job ${result.rows[0].id}: payload ${JSON.stringify(payload)}, priority ${priority}, maxAttempts ${maxAttempts} jobType ${jobType}, tags ${JSON.stringify(tags)}`,\n );\n }\n await recordJobEvent(pool, result.rows[0].id, JobEventType.Added, {\n jobType,\n payload,\n tags,\n });\n return result.rows[0].id;\n } catch (error) {\n log(`Error adding job: ${error}`);\n throw error;\n } finally {\n client.release();\n }\n};\n\n/**\n * Get a job by ID\n */\nexport const getJob = async <PayloadMap, T extends keyof PayloadMap & string>(\n pool: Pool,\n id: number,\n): Promise<JobRecord<PayloadMap, T> | null> => {\n const client = await pool.connect();\n try {\n const result = await client.query(\n `SELECT id, job_type AS \"jobType\", payload, status, max_attempts AS \"maxAttempts\", attempts, priority, run_at AS \"runAt\", timeout_ms AS \"timeoutMs\", created_at AS \"createdAt\", updated_at AS \"updatedAt\", started_at AS \"startedAt\", completed_at AS \"completedAt\", last_failed_at AS \"lastFailedAt\", locked_at AS \"lockedAt\", locked_by AS \"lockedBy\", error_history AS \"errorHistory\", failure_reason AS \"failureReason\", next_attempt_at AS \"nextAttemptAt\", last_failed_at AS \"lastFailedAt\", last_retried_at AS \"lastRetriedAt\", last_cancelled_at AS \"lastCancelledAt\", pending_reason AS \"pendingReason\" FROM job_queue WHERE id = $1`,\n [id],\n );\n\n if (result.rows.length === 0) {\n log(`Job ${id} not found`);\n return null;\n }\n\n log(`Found job ${id}`);\n\n const job = result.rows[0] as JobRecord<PayloadMap, T>;\n\n return {\n ...job,\n payload: job.payload,\n timeoutMs: job.timeoutMs,\n failureReason: job.failureReason,\n };\n } catch (error) {\n log(`Error getting job ${id}: ${error}`);\n throw error;\n } finally {\n client.release();\n }\n};\n\n/**\n * Get jobs by status\n */\nexport const getJobsByStatus = async <\n PayloadMap,\n T extends keyof PayloadMap & string,\n>(\n pool: Pool,\n status: string,\n limit = 100,\n offset = 0,\n): Promise<JobRecord<PayloadMap, T>[]> => {\n const client = await pool.connect();\n try {\n const result = await client.query(\n `SELECT id, job_type AS \"jobType\", payload, status, max_attempts AS \"maxAttempts\", attempts, priority, run_at AS \"runAt\", timeout_ms AS \"timeoutMs\", created_at AS \"createdAt\", updated_at AS \"updatedAt\", started_at AS \"startedAt\", completed_at AS \"completedAt\", last_failed_at AS \"lastFailedAt\", locked_at AS \"lockedAt\", locked_by AS \"lockedBy\", error_history AS \"errorHistory\", failure_reason AS \"failureReason\", next_attempt_at AS \"nextAttemptAt\", last_failed_at AS \"lastFailedAt\", last_retried_at AS \"lastRetriedAt\", last_cancelled_at AS \"lastCancelledAt\", pending_reason AS \"pendingReason\" FROM job_queue WHERE status = $1 ORDER BY created_at DESC LIMIT $2 OFFSET $3`,\n [status, limit, offset],\n );\n\n log(`Found ${result.rows.length} jobs by status ${status}`);\n\n return result.rows.map((job) => ({\n ...job,\n payload: job.payload,\n timeoutMs: job.timeoutMs,\n failureReason: job.failureReason,\n }));\n } catch (error) {\n log(`Error getting jobs by status ${status}: ${error}`);\n throw error;\n } finally {\n client.release();\n }\n};\n\n/**\n * Get the next batch of jobs to process\n * @param pool - The database pool\n * @param workerId - The worker ID\n * @param batchSize - The batch size\n * @param jobType - Only fetch jobs with this job type (string or array of strings)\n */\nexport const getNextBatch = async <\n PayloadMap,\n T extends keyof PayloadMap & string,\n>(\n pool: Pool,\n workerId: string,\n batchSize = 10,\n jobType?: string | string[],\n): Promise<JobRecord<PayloadMap, T>[]> => {\n const client = await pool.connect();\n try {\n // Begin transaction\n await client.query('BEGIN');\n\n // Build job type filter\n let jobTypeFilter = '';\n let params: any[] = [workerId, batchSize];\n if (jobType) {\n if (Array.isArray(jobType)) {\n jobTypeFilter = ` AND job_type = ANY($3)`;\n params.push(jobType);\n } else {\n jobTypeFilter = ` AND job_type = $3`;\n params.push(jobType);\n }\n }\n\n // Get and lock a batch of jobs\n const result = await client.query(\n `\n UPDATE job_queue\n SET status = 'processing', \n locked_at = NOW(), \n locked_by = $1,\n attempts = attempts + 1,\n updated_at = NOW(),\n pending_reason = NULL,\n started_at = COALESCE(started_at, NOW()),\n last_retried_at = CASE WHEN attempts > 0 THEN NOW() ELSE last_retried_at END\n WHERE id IN (\n SELECT id FROM job_queue\n WHERE (status = 'pending' OR (status = 'failed' AND next_attempt_at <= NOW()))\n AND (attempts < max_attempts)\n AND run_at <= NOW()\n ${jobTypeFilter}\n ORDER BY priority DESC, created_at ASC\n LIMIT $2\n FOR UPDATE SKIP LOCKED\n )\n RETURNING id, job_type AS \"jobType\", payload, status, max_attempts AS \"maxAttempts\", attempts, priority, run_at AS \"runAt\", timeout_ms AS \"timeoutMs\", created_at AS \"createdAt\", updated_at AS \"updatedAt\", started_at AS \"startedAt\", completed_at AS \"completedAt\", last_failed_at AS \"lastFailedAt\", locked_at AS \"lockedAt\", locked_by AS \"lockedBy\", error_history AS \"errorHistory\", failure_reason AS \"failureReason\", next_attempt_at AS \"nextAttemptAt\", last_retried_at AS \"lastRetriedAt\", last_cancelled_at AS \"lastCancelledAt\", pending_reason AS \"pendingReason\"\n `,\n params,\n );\n\n log(`Found ${result.rows.length} jobs to process`);\n\n // Commit transaction\n await client.query('COMMIT');\n\n // Record processing event for each job\n for (const row of result.rows) {\n await recordJobEvent(pool, row.id, JobEventType.Processing);\n }\n\n return result.rows.map((job) => ({\n ...job,\n payload: job.payload,\n timeoutMs: job.timeoutMs,\n }));\n } catch (error) {\n log(`Error getting next batch: ${error}`);\n await client.query('ROLLBACK');\n throw error;\n } finally {\n client.release();\n }\n};\n\n/**\n * Mark a job as completed\n */\nexport const completeJob = async (pool: Pool, jobId: number): Promise<void> => {\n const client = await pool.connect();\n try {\n await client.query(\n `\n UPDATE job_queue\n SET status = 'completed', updated_at = NOW(), completed_at = NOW()\n WHERE id = $1\n `,\n [jobId],\n );\n await recordJobEvent(pool, jobId, JobEventType.Completed);\n } catch (error) {\n log(`Error completing job ${jobId}: ${error}`);\n throw error;\n } finally {\n log(`Completed job ${jobId}`);\n client.release();\n }\n};\n\n/**\n * Mark a job as failed\n */\nexport const failJob = async (\n pool: Pool,\n jobId: number,\n error: Error,\n failureReason?: FailureReason,\n): Promise<void> => {\n const client = await pool.connect();\n try {\n /**\n * The next attempt will be scheduled after `2^attempts * 1 minute` from the last attempt.\n */\n await client.query(\n `\n UPDATE job_queue\n SET status = 'failed', \n updated_at = NOW(),\n next_attempt_at = CASE \n WHEN attempts < max_attempts THEN NOW() + (POWER(2, attempts) * INTERVAL '1 minute')\n ELSE NULL\n END,\n error_history = COALESCE(error_history, '[]'::jsonb) || $2::jsonb,\n failure_reason = $3,\n last_failed_at = NOW()\n WHERE id = $1\n `,\n [\n jobId,\n JSON.stringify([\n {\n message: error.message || String(error),\n timestamp: new Date().toISOString(),\n },\n ]),\n failureReason ?? null,\n ],\n );\n await recordJobEvent(pool, jobId, JobEventType.Failed, {\n message: error.message || String(error),\n failureReason,\n });\n } catch (error) {\n log(`Error failing job ${jobId}: ${error}`);\n throw error;\n } finally {\n log(`Failed job ${jobId}`);\n client.release();\n }\n};\n\n/**\n * Retry a failed job immediately\n */\nexport const retryJob = async (pool: Pool, jobId: number): Promise<void> => {\n const client = await pool.connect();\n try {\n await client.query(\n `\n UPDATE job_queue\n SET status = 'pending', \n updated_at = NOW(),\n locked_at = NULL,\n locked_by = NULL,\n next_attempt_at = NOW(),\n last_retried_at = NOW()\n WHERE id = $1\n `,\n [jobId],\n );\n await recordJobEvent(pool, jobId, JobEventType.Retried);\n } catch (error) {\n log(`Error retrying job ${jobId}: ${error}`);\n throw error;\n } finally {\n log(`Retried job ${jobId}`);\n client.release();\n }\n};\n\n/**\n * Delete old completed jobs\n */\nexport const cleanupOldJobs = async (\n pool: Pool,\n daysToKeep = 30,\n): Promise<number> => {\n const client = await pool.connect();\n try {\n const result = await client.query(`\n DELETE FROM job_queue\n WHERE status = 'completed'\n AND updated_at < NOW() - INTERVAL '${daysToKeep} days'\n RETURNING id\n `);\n log(`Deleted ${result.rowCount} old jobs`);\n return result.rowCount || 0;\n } catch (error) {\n log(`Error cleaning up old jobs: ${error}`);\n throw error;\n } finally {\n client.release();\n }\n};\n\n/**\n * Cancel a scheduled job (only if still pending)\n */\nexport const cancelJob = async (pool: Pool, jobId: number): Promise<void> => {\n const client = await pool.connect();\n try {\n await client.query(\n `\n UPDATE job_queue\n SET status = 'cancelled', updated_at = NOW(), last_cancelled_at = NOW()\n WHERE id = $1 AND status = 'pending'\n `,\n [jobId],\n );\n await recordJobEvent(pool, jobId, JobEventType.Cancelled);\n } catch (error) {\n log(`Error cancelling job ${jobId}: ${error}`);\n throw error;\n } finally {\n log(`Cancelled job ${jobId}`);\n client.release();\n }\n};\n\n/**\n * Cancel all upcoming jobs (pending and scheduled in the future) with optional filters\n */\nexport const cancelAllUpcomingJobs = async (\n pool: Pool,\n filters?: {\n jobType?: string;\n priority?: number;\n runAt?: Date;\n tags?: { values: string[]; mode?: TagQueryMode };\n },\n): Promise<number> => {\n const client = await pool.connect();\n try {\n let query = `\n UPDATE job_queue\n SET status = 'cancelled', updated_at = NOW()\n WHERE status = 'pending'`;\n const params: any[] = [];\n let paramIdx = 1;\n if (filters) {\n if (filters.jobType) {\n query += ` AND job_type = $${paramIdx++}`;\n params.push(filters.jobType);\n }\n if (filters.priority !== undefined) {\n query += ` AND priority = $${paramIdx++}`;\n params.push(filters.priority);\n }\n if (filters.runAt) {\n query += ` AND run_at = $${paramIdx++}`;\n params.push(filters.runAt);\n }\n if (\n filters.tags &&\n filters.tags.values &&\n filters.tags.values.length > 0\n ) {\n const mode = filters.tags.mode || 'all';\n const tagValues = filters.tags.values;\n switch (mode) {\n case 'exact':\n query += ` AND tags = $${paramIdx++}`;\n params.push(tagValues);\n break;\n case 'all':\n query += ` AND tags @> $${paramIdx++}`;\n params.push(tagValues);\n break;\n case 'any':\n query += ` AND tags && $${paramIdx++}`;\n params.push(tagValues);\n break;\n case 'none':\n query += ` AND NOT (tags && $${paramIdx++})`;\n params.push(tagValues);\n break;\n default:\n query += ` AND tags @> $${paramIdx++}`;\n params.push(tagValues);\n }\n }\n }\n query += '\\nRETURNING id';\n const result = await client.query(query, params);\n log(`Cancelled ${result.rowCount} jobs`);\n return result.rowCount || 0;\n } catch (error) {\n log(`Error cancelling upcoming jobs: ${error}`);\n throw error;\n } finally {\n client.release();\n }\n};\n\n/**\n * Get all jobs with optional pagination\n */\nexport const getAllJobs = async <\n PayloadMap,\n T extends keyof PayloadMap & string,\n>(\n pool: Pool,\n limit = 100,\n offset = 0,\n): Promise<JobRecord<PayloadMap, T>[]> => {\n const client = await pool.connect();\n try {\n const result = await client.query(\n `SELECT id, job_type AS \"jobType\", payload, status, max_attempts AS \"maxAttempts\", attempts, priority, run_at AS \"runAt\", timeout_ms AS \"timeoutMs\", created_at AS \"createdAt\", updated_at AS \"updatedAt\", started_at AS \"startedAt\", completed_at AS \"completedAt\", last_failed_at AS \"lastFailedAt\", locked_at AS \"lockedAt\", locked_by AS \"lockedBy\", error_history AS \"errorHistory\", failure_reason AS \"failureReason\", next_attempt_at AS \"nextAttemptAt\", last_failed_at AS \"lastFailedAt\", last_retried_at AS \"lastRetriedAt\", last_cancelled_at AS \"lastCancelledAt\", pending_reason AS \"pendingReason\" FROM job_queue ORDER BY created_at DESC LIMIT $1 OFFSET $2`,\n [limit, offset],\n );\n log(`Found ${result.rows.length} jobs (all)`);\n return result.rows.map((job) => ({\n ...job,\n payload: job.payload,\n timeoutMs: job.timeoutMs,\n }));\n } catch (error) {\n log(`Error getting all jobs: ${error}`);\n throw error;\n } finally {\n client.release();\n }\n};\n\n/**\n * Set a pending reason for unpicked jobs\n */\nexport const setPendingReasonForUnpickedJobs = async (\n pool: Pool,\n reason: string,\n jobType?: string | string[],\n) => {\n const client = await pool.connect();\n try {\n let jobTypeFilter = '';\n let params: any[] = [reason];\n if (jobType) {\n if (Array.isArray(jobType)) {\n jobTypeFilter = ` AND job_type = ANY($2)`;\n params.push(jobType);\n } else {\n jobTypeFilter = ` AND job_type = $2`;\n params.push(jobType);\n }\n }\n await client.query(\n `UPDATE job_queue SET pending_reason = $1 WHERE status = 'pending'${jobTypeFilter}`,\n params,\n );\n } finally {\n client.release();\n }\n};\n\n/**\n * Reclaim jobs stuck in 'processing' for too long.\n *\n * If a process (e.g., API route or worker) crashes after marking a job as 'processing' but before completing it, the job can remain stuck in the 'processing' state indefinitely. This can happen if the process is killed or encounters an unhandled error after updating the job status but before marking it as 'completed' or 'failed'.\n * @param pool - The database pool\n * @param maxProcessingTimeMinutes - Max allowed processing time in minutes (default: 10)\n * @returns Number of jobs reclaimed\n */\nexport const reclaimStuckJobs = async (\n pool: Pool,\n maxProcessingTimeMinutes = 10,\n): Promise<number> => {\n const client = await pool.connect();\n try {\n const result = await client.query(\n `\n UPDATE job_queue\n SET status = 'pending', locked_at = NULL, locked_by = NULL, updated_at = NOW()\n WHERE status = 'processing'\n AND locked_at < NOW() - INTERVAL '${maxProcessingTimeMinutes} minutes'\n RETURNING id\n `,\n );\n log(`Reclaimed ${result.rowCount} stuck jobs`);\n return result.rowCount || 0;\n } catch (error) {\n log(`Error reclaiming stuck jobs: ${error}`);\n throw error;\n } finally {\n client.release();\n }\n};\n\n/**\n * Get all events for a job, ordered by createdAt ascending\n */\nexport const getJobEvents = async (\n pool: Pool,\n jobId: number,\n): Promise<JobEvent[]> => {\n const client = await pool.connect();\n try {\n const res = await client.query(\n `SELECT id, job_id AS \"jobId\", event_type AS \"eventType\", metadata, created_at AS \"createdAt\" FROM job_events WHERE job_id = $1 ORDER BY created_at ASC`,\n [jobId],\n );\n return res.rows as JobEvent[];\n } finally {\n client.release();\n }\n};\n\n/**\n * Get jobs by tags (matches all specified tags)\n */\nexport const getJobsByTags = async <\n PayloadMap,\n T extends keyof PayloadMap & string,\n>(\n pool: Pool,\n tags: string[],\n mode: TagQueryMode = 'all',\n limit = 100,\n offset = 0,\n): Promise<JobRecord<PayloadMap, T>[]> => {\n const client = await pool.connect();\n try {\n let query = `SELECT id, job_type AS \"jobType\", payload, status, max_attempts AS \"maxAttempts\", attempts, priority, run_at AS \"runAt\", timeout_ms AS \"timeoutMs\", created_at AS \"createdAt\", updated_at AS \"updatedAt\", started_at AS \"startedAt\", completed_at AS \"completedAt\", last_failed_at AS \"lastFailedAt\", locked_at AS \"lockedAt\", locked_by AS \"lockedBy\", error_history AS \"errorHistory\", failure_reason AS \"failureReason\", next_attempt_at AS \"nextAttemptAt\", last_failed_at AS \"lastFailedAt\", last_retried_at AS \"lastRetriedAt\", last_cancelled_at AS \"lastCancelledAt\", pending_reason AS \"pendingReason\", tags\n FROM job_queue`;\n let params: any[] = [];\n switch (mode) {\n case 'exact':\n query += ' WHERE tags = $1';\n params = [tags];\n break;\n case 'all':\n query += ' WHERE tags @> $1';\n params = [tags];\n break;\n case 'any':\n query += ' WHERE tags && $1';\n params = [tags];\n break;\n case 'none':\n query += ' WHERE NOT (tags && $1)';\n params = [tags];\n break;\n default:\n query += ' WHERE tags @> $1';\n params = [tags];\n }\n query += ' ORDER BY created_at DESC LIMIT $2 OFFSET $3';\n params.push(limit, offset);\n const result = await client.query(query, params);\n log(\n `Found ${result.rows.length} jobs by tags ${JSON.stringify(tags)} (mode: ${mode})`,\n );\n return result.rows.map((job) => ({\n ...job,\n payload: job.payload,\n timeoutMs: job.timeoutMs,\n failureReason: job.failureReason,\n }));\n } catch (error) {\n log(\n `Error getting jobs by tags ${JSON.stringify(tags)} (mode: ${mode}): ${error}`,\n );\n throw error;\n } finally {\n client.release();\n }\n};\n","import { Pool } from 'pg';\nimport {\n JobRecord,\n ProcessorOptions,\n Processor,\n JobHandler,\n JobType,\n FailureReason,\n JobHandlers,\n} from './types.js';\nimport {\n getNextBatch,\n completeJob,\n failJob,\n setPendingReasonForUnpickedJobs,\n} from './queue.js';\nimport { log, setLogContext } from './log-context.js';\n\n/**\n * Process a single job using the provided handler map\n */\nexport async function processJobWithHandlers<\n PayloadMap,\n T extends keyof PayloadMap & string,\n>(\n pool: Pool,\n job: JobRecord<PayloadMap, T>,\n jobHandlers: JobHandlers<PayloadMap>,\n): Promise<void> {\n const handler = jobHandlers[job.jobType];\n\n if (!handler) {\n await setPendingReasonForUnpickedJobs(\n pool,\n `No handler registered for job type: ${job.jobType}`,\n job.jobType,\n );\n await failJob(\n pool,\n job.id,\n new Error(`No handler registered for job type: ${job.jobType}`),\n FailureReason.NoHandler,\n );\n return;\n }\n\n // Per-job timeout logic\n const timeoutMs = job.timeoutMs ?? undefined;\n let timeoutId: NodeJS.Timeout | undefined;\n const controller = new AbortController();\n try {\n const jobPromise = handler(job.payload, controller.signal);\n if (timeoutMs && timeoutMs > 0) {\n await Promise.race([\n jobPromise,\n new Promise((_, reject) => {\n timeoutId = setTimeout(() => {\n controller.abort();\n const timeoutError = new Error(\n `Job timed out after ${timeoutMs} ms`,\n );\n // @ts-ignore\n timeoutError.failureReason = FailureReason.Timeout;\n reject(timeoutError);\n }, timeoutMs);\n }),\n ]);\n } else {\n await jobPromise;\n }\n if (timeoutId) clearTimeout(timeoutId);\n await completeJob(pool, job.id);\n } catch (error) {\n if (timeoutId) clearTimeout(timeoutId);\n console.error(`Error processing job ${job.id}:`, error);\n let failureReason = FailureReason.HandlerError;\n if (\n error &&\n typeof error === 'object' &&\n 'failureReason' in error &&\n (error as any).failureReason === FailureReason.Timeout\n ) {\n failureReason = FailureReason.Timeout;\n }\n await failJob(\n pool,\n job.id,\n error instanceof Error ? error : new Error(String(error)),\n failureReason,\n );\n }\n}\n\n/**\n * Process a batch of jobs using the provided handler map and concurrency limit\n */\nexport async function processBatchWithHandlers<PayloadMap>(\n pool: Pool,\n workerId: string,\n batchSize: number,\n jobType: string | string[] | undefined,\n jobHandlers: JobHandlers<PayloadMap>,\n concurrency?: number,\n): Promise<number> {\n const jobs = await getNextBatch<PayloadMap, JobType<PayloadMap>>(\n pool,\n workerId,\n batchSize,\n jobType,\n );\n if (!concurrency || concurrency >= jobs.length) {\n // Default: all in parallel\n await Promise.all(\n jobs.map((job) => processJobWithHandlers(pool, job, jobHandlers)),\n );\n return jobs.length;\n }\n // Concurrency-limited pool\n let idx = 0;\n let running = 0;\n let finished = 0;\n return new Promise((resolve, reject) => {\n const next = () => {\n if (finished === jobs.length) return resolve(jobs.length);\n while (running < concurrency && idx < jobs.length) {\n const job = jobs[idx++];\n running++;\n processJobWithHandlers(pool, job, jobHandlers)\n .then(() => {\n running--;\n finished++;\n next();\n })\n .catch((err) => {\n running--;\n finished++;\n next();\n });\n }\n };\n next();\n });\n}\n\n/**\n * Start a job processor that continuously processes jobs\n * @param pool - The database pool\n * @param handlers - The job handlers for this processor instance\n * @param options - The processor options. Leave pollInterval empty to run only once. Use jobType to filter jobs by type.\n * @returns {Processor} The processor instance\n */\nexport const createProcessor = <PayloadMap = any>(\n pool: Pool,\n handlers: JobHandlers<PayloadMap>,\n options: ProcessorOptions = {},\n): Processor => {\n const {\n workerId = `worker-${Math.random().toString(36).substring(2, 9)}`,\n batchSize = 10,\n pollInterval = 5000,\n onError = (error: Error) => console.error('Job processor error:', error),\n jobType,\n concurrency = 3,\n } = options;\n\n let running = false;\n let intervalId: NodeJS.Timeout | null = null;\n\n setLogContext(options.verbose ?? false);\n\n const processJobs = async (): Promise<number> => {\n if (!running) return 0;\n\n log(\n `Processing jobs with workerId: ${workerId}${jobType ? ` and jobType: ${Array.isArray(jobType) ? jobType.join(',') : jobType}` : ''}`,\n );\n\n try {\n const processed = await processBatchWithHandlers(\n pool,\n workerId,\n batchSize,\n jobType,\n handlers,\n concurrency,\n );\n // Only process one batch in start; do not schedule next batch here\n return processed;\n } catch (error) {\n onError(error instanceof Error ? error : new Error(String(error)));\n }\n return 0;\n };\n\n return {\n /**\n * Start the job processor in the background.\n * - This will run periodically (every pollInterval milliseconds or 5 seconds if not provided) and process jobs as they become available.\n * - You have to call the stop method to stop the processor.\n */\n startInBackground: () => {\n if (running) return;\n\n log(`Starting job processor with workerId: ${workerId}`);\n running = true;\n // Background: process batches repeatedly if needed\n const processBatches = async () => {\n if (!running) return;\n const processed = await processJobs();\n if (processed === batchSize && running) {\n setImmediate(processBatches);\n }\n };\n processBatches(); // Process immediately on start\n intervalId = setInterval(processJobs, pollInterval);\n },\n /**\n * Stop the job processor that runs in the background\n */\n stop: () => {\n log(`Stopping job processor with workerId: ${workerId}`);\n running = false;\n if (intervalId) {\n clearInterval(intervalId);\n intervalId = null;\n }\n },\n /**\n * Start the job processor synchronously.\n * - This will process all jobs immediately and then stop.\n * - The pollInterval is ignored.\n */\n start: async () => {\n log(`Starting job processor with workerId: ${workerId}`);\n running = true;\n const processed = await processJobs();\n running = false;\n return processed;\n },\n isRunning: () => running,\n };\n};\n","import { Pool } from 'pg';\nimport { JobQueueConfig } from './types.js';\nimport { parse } from 'pg-connection-string';\n\n// Create a database connection pool\nexport const createPool = (config: JobQueueConfig['databaseConfig']): Pool => {\n let searchPath: string | undefined;\n if (config.connectionString) {\n // Parse the connection string to extract search_path from query params\n try {\n const url = new URL(config.connectionString);\n searchPath = url.searchParams.get('search_path') || undefined;\n } catch (e) {\n // fallback: try pg-connection-string parse (for non-standard URLs)\n const parsed = parse(config.connectionString);\n if (parsed.options) {\n // options might look like '-c search_path=myschema'\n const match = parsed.options.match(/search_path=([^\\s]+)/);\n if (match) {\n searchPath = match[1];\n }\n }\n }\n }\n\n const pool = new Pool(config);\n\n // If search_path is specified, set it for every new connection\n if (searchPath) {\n pool.on('connect', (client) => {\n client.query(`SET search_path TO ${searchPath}`);\n });\n }\n\n return pool;\n};\n","import {\n addJob,\n getJob,\n getJobsByStatus,\n retryJob,\n cleanupOldJobs,\n cancelJob,\n cancelAllUpcomingJobs,\n getAllJobs,\n reclaimStuckJobs,\n getJobEvents,\n getJobsByTags,\n} from './queue.js';\nimport { createProcessor } from './processor.js';\nimport {\n JobQueueConfig,\n JobQueue,\n JobOptions,\n ProcessorOptions,\n JobHandlers,\n} from './types.js';\nimport { setLogContext } from './log-context.js';\nimport { createPool } from './db-util.js';\n\n/**\n * Initialize the job queue system\n */\nexport const initJobQueue = <PayloadMap = any>(\n config: JobQueueConfig,\n): JobQueue<PayloadMap> => {\n const { databaseConfig } = config;\n\n // Create database pool\n const pool = createPool(databaseConfig);\n\n setLogContext(config.verbose ?? false);\n\n // Return the job queue API\n return {\n // Job queue operations\n addJob: withLogContext(\n (job: JobOptions<PayloadMap, any>) => addJob<PayloadMap, any>(pool, job),\n config.verbose ?? false,\n ),\n getJob: withLogContext(\n (id: number) => getJob<PayloadMap, any>(pool, id),\n config.verbose ?? false,\n ),\n getJobsByStatus: withLogContext(\n (status: string, limit?: number, offset?: number) =>\n getJobsByStatus<PayloadMap, any>(pool, status, limit, offset),\n config.verbose ?? false,\n ),\n getAllJobs: withLogContext(\n (limit?: number, offset?: number) =>\n getAllJobs<PayloadMap, any>(pool, limit, offset),\n config.verbose ?? false,\n ),\n retryJob: (jobId: number) => retryJob(pool, jobId),\n cleanupOldJobs: (daysToKeep?: number) => cleanupOldJobs(pool, daysToKeep),\n cancelJob: withLogContext(\n (jobId: number) => cancelJob(pool, jobId),\n config.verbose ?? false,\n ),\n cancelAllUpcomingJobs: withLogContext(\n (filters?: {\n jobType?: string;\n priority?: number;\n runAt?: Date;\n tags?: { values: string[]; mode?: import('./types.js').TagQueryMode };\n }) => cancelAllUpcomingJobs(pool, filters),\n config.verbose ?? false,\n ),\n reclaimStuckJobs: withLogContext(\n (maxProcessingTimeMinutes?: number) =>\n reclaimStuckJobs(pool, maxProcessingTimeMinutes),\n config.verbose ?? false,\n ),\n getJobsByTags: withLogContext(\n (tags: string[], mode = 'all', limit?: number, offset?: number) =>\n getJobsByTags<PayloadMap, any>(pool, tags, mode, limit, offset),\n config.verbose ?? false,\n ),\n\n // Job processing\n createProcessor: (\n handlers: JobHandlers<PayloadMap>,\n options?: ProcessorOptions,\n ) => createProcessor<PayloadMap>(pool, handlers, options),\n // Advanced access (for custom operations)\n getPool: () => pool,\n // Job events\n getJobEvents: withLogContext(\n (jobId: number) => getJobEvents(pool, jobId),\n config.verbose ?? false,\n ),\n };\n};\n\nconst withLogContext =\n <T>(fn: (...args: any[]) => T, verbose: boolean) =>\n (...args: Parameters<typeof fn>): ReturnType<typeof fn> => {\n setLogContext(verbose);\n return fn(...args);\n };\n\nexport * from './types.js';\n"]}
1
+ {"version":3,"sources":["../src/types.ts","../src/log-context.ts","../src/queue.ts","../src/processor.ts","../src/db-util.ts","../src/index.ts"],"names":["JobEventType","FailureReason","AsyncLocalStorage","error","fs","parse","Pool"],"mappings":"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","file":"index.cjs","sourcesContent":["import { Pool } from 'pg';\n\n// Utility type for job type keys\nexport type JobType<PayloadMap> = keyof PayloadMap & string;\n\nexport interface JobOptions<PayloadMap, T extends JobType<PayloadMap>> {\n jobType: T;\n payload: PayloadMap[T];\n maxAttempts?: number;\n priority?: number;\n runAt?: Date | null;\n /**\n * Timeout for this job in milliseconds. If not set, uses the processor default or unlimited.\n */\n timeoutMs?: number;\n /**\n * Tags for this job. Used for grouping, searching, or batch operations.\n */\n tags?: string[];\n}\n\nexport enum JobEventType {\n Added = 'added',\n Processing = 'processing',\n Completed = 'completed',\n Failed = 'failed',\n Cancelled = 'cancelled',\n Retried = 'retried',\n}\n\nexport interface JobEvent {\n id: number;\n jobId: number;\n eventType: JobEventType;\n createdAt: Date;\n metadata: any;\n}\n\nexport enum FailureReason {\n Timeout = 'timeout',\n HandlerError = 'handler_error',\n NoHandler = 'no_handler',\n}\n\nexport type JobStatus =\n | 'pending'\n | 'processing'\n | 'completed'\n | 'failed'\n | 'cancelled';\n\nexport interface JobRecord<PayloadMap, T extends JobType<PayloadMap>> {\n id: number;\n jobType: T;\n payload: PayloadMap[T];\n status: JobStatus;\n createdAt: Date;\n updatedAt: Date;\n lockedAt: Date | null;\n lockedBy: string | null;\n attempts: number;\n maxAttempts: number;\n nextAttemptAt: Date | null;\n priority: number;\n runAt: Date;\n pendingReason?: string | null;\n errorHistory?: { message: string; timestamp: string }[];\n /**\n * Timeout for this job in milliseconds (null means no timeout).\n */\n timeoutMs?: number | null;\n /**\n * The reason for the last failure, if any.\n */\n failureReason?: FailureReason | null;\n /**\n * The time the job was completed, if completed.\n */\n completedAt: Date | null;\n /**\n * The time the job was first picked up for processing.\n */\n startedAt: Date | null;\n /**\n * The time the job was last retried.\n */\n lastRetriedAt: Date | null;\n /**\n * The time the job last failed.\n */\n lastFailedAt: Date | null;\n /**\n * The time the job was last cancelled.\n */\n lastCancelledAt: Date | null;\n /**\n * Tags for this job. Used for grouping, searching, or batch operations.\n */\n tags?: string[];\n}\n\nexport type JobHandler<PayloadMap, T extends keyof PayloadMap> = (\n payload: PayloadMap[T],\n signal: AbortSignal,\n) => Promise<void>;\n\nexport type JobHandlers<PayloadMap> = {\n [K in keyof PayloadMap]: JobHandler<PayloadMap, K>;\n};\n\nexport interface ProcessorOptions {\n workerId?: string;\n /**\n * The number of jobs to process at a time.\n * - If not provided, the processor will process 10 jobs at a time.\n * - In serverless functions, it's better to process less jobs at a time since serverless functions are charged by the second and have a timeout.\n */\n batchSize?: number;\n /**\n * The maximum number of jobs to process in parallel per batch.\n * - If not provided, all jobs in the batch are processed in parallel.\n * - Set to 1 to process jobs sequentially.\n * - Set to a lower value to avoid resource exhaustion.\n */\n concurrency?: number;\n /**\n * The interval in milliseconds to poll for new jobs.\n * - If not provided, the processor will process jobs every 5 seconds when startInBackground is called.\n * - In serverless functions, it's better to leave this empty.\n * - If you call start instead of startInBackground, the pollInterval is ignored.\n */\n pollInterval?: number;\n onError?: (error: Error) => void;\n verbose?: boolean;\n /**\n * Only process jobs with this job type (string or array of strings). If omitted, all job types are processed.\n */\n jobType?: string | string[];\n}\n\nexport interface Processor {\n /**\n * Start the job processor in the background.\n * - This will run periodically (every pollInterval milliseconds or 5 seconds if not provided) and process jobs (as many as batchSize) as they become available.\n * - **You have to call the stop method to stop the processor.**\n * - Handlers are provided per-processor when calling createProcessor.\n * - In serverless functions, it's recommended to call start instead and await it to finish.\n */\n startInBackground: () => void;\n /**\n * Stop the job processor that runs in the background.\n */\n stop: () => void;\n /**\n * Check if the job processor is running.\n */\n isRunning: () => boolean;\n /**\n * Start the job processor synchronously.\n * - This will process jobs (as many as batchSize) immediately and then stop. The pollInterval is ignored.\n * - In serverless functions, it's recommended to use this instead of startInBackground.\n * - Returns the number of jobs processed.\n */\n start: () => Promise<number>;\n}\n\nexport interface DatabaseSSLConfig {\n /**\n * CA certificate as PEM string or file path. If the value starts with 'file://', it will be loaded from file, otherwise treated as PEM string.\n */\n ca?: string;\n /**\n * Client certificate as PEM string or file path. If the value starts with 'file://', it will be loaded from file, otherwise treated as PEM string.\n */\n cert?: string;\n /**\n * Client private key as PEM string or file path. If the value starts with 'file://', it will be loaded from file, otherwise treated as PEM string.\n */\n key?: string;\n /**\n * Whether to reject unauthorized certificates (default: true)\n */\n rejectUnauthorized?: boolean;\n}\n\nexport interface JobQueueConfig {\n databaseConfig: {\n connectionString?: string;\n host?: string;\n port?: number;\n database?: string;\n user?: string;\n password?: string;\n ssl?: DatabaseSSLConfig;\n };\n verbose?: boolean;\n}\n\nexport type TagQueryMode = 'exact' | 'all' | 'any' | 'none';\n\nexport interface JobQueue<PayloadMap> {\n /**\n * Add a job to the job queue.\n */\n addJob: <T extends JobType<PayloadMap>>(\n job: JobOptions<PayloadMap, T>,\n ) => Promise<number>;\n /**\n * Get a job by its ID.\n */\n getJob: <T extends JobType<PayloadMap>>(\n id: number,\n ) => Promise<JobRecord<PayloadMap, T> | null>;\n /**\n * Get jobs by their status, with pagination.\n * - If no limit is provided, all jobs are returned.\n * - If no offset is provided, the first page is returned.\n * - The jobs are returned in descending order of createdAt.\n */\n getJobsByStatus: <T extends JobType<PayloadMap>>(\n status: JobStatus,\n limit?: number,\n offset?: number,\n ) => Promise<JobRecord<PayloadMap, T>[]>;\n /**\n * Get jobs by tag(s).\n * - Modes:\n * - 'exact': Jobs with exactly the same tags (no more, no less)\n * - 'all': Jobs that have all the given tags (can have more)\n * - 'any': Jobs that have at least one of the given tags\n * - 'none': Jobs that have none of the given tags\n * - Default mode is 'all'.\n */\n getJobsByTags: <T extends JobType<PayloadMap>>(\n tags: string[],\n mode?: TagQueryMode,\n limit?: number,\n offset?: number,\n ) => Promise<JobRecord<PayloadMap, T>[]>;\n /**\n * Get all jobs.\n */\n getAllJobs: <T extends JobType<PayloadMap>>(\n limit?: number,\n offset?: number,\n ) => Promise<JobRecord<PayloadMap, T>[]>;\n /**\n * Get jobs by filters.\n /**\n * Get jobs by filters.\n */\n getJobs: <T extends JobType<PayloadMap>>(filters?: {\n jobType?: string;\n priority?: number;\n runAt?: Date | { gt?: Date; gte?: Date; lt?: Date; lte?: Date; eq?: Date };\n tags?: { values: string[]; mode?: TagQueryMode };\n }) => Promise<JobRecord<PayloadMap, T>[]>;\n /**\n * Retry a job given its ID.\n * - This will set the job status back to 'pending', clear the locked_at and locked_by, and allow it to be picked up by other workers.\n */\n retryJob: (jobId: number) => Promise<void>;\n /**\n * Cleanup jobs that are older than the specified number of days.\n */\n cleanupOldJobs: (daysToKeep?: number) => Promise<number>;\n /**\n * Cancel a job given its ID.\n * - This will set the job status to 'cancelled' and clear the locked_at and locked_by.\n */\n cancelJob: (jobId: number) => Promise<void>;\n /**\n * Reclaim stuck jobs.\n * - If a process (e.g., API route or worker) crashes after marking a job as 'processing' but before completing it, the job can remain stuck in the 'processing' state indefinitely. This can happen if the process is killed or encounters an unhandled error after updating the job status but before marking it as 'completed' or 'failed'.\n * - This function will set the job status back to 'pending', clear the locked_at and locked_by, and allow it to be picked up by other workers.\n * - The default max processing time is 10 minutes.\n */\n reclaimStuckJobs: (maxProcessingTimeMinutes?: number) => Promise<number>;\n /**\n * Cancel all upcoming jobs that match the filters.\n * - If no filters are provided, all upcoming jobs are cancelled.\n * - If filters are provided, only jobs that match the filters are cancelled.\n * - The filters are:\n * - jobType: The job type to cancel.\n * - priority: The priority of the job to cancel.\n * - runAt: The time the job is scheduled to run at (now supports gt/gte/lt/lte/eq).\n * - tags: An object with 'values' (string[]) and 'mode' (TagQueryMode) for tag-based cancellation.\n */\n cancelAllUpcomingJobs: (filters?: {\n jobType?: string;\n priority?: number;\n runAt?: Date | { gt?: Date; gte?: Date; lt?: Date; lte?: Date; eq?: Date };\n tags?: { values: string[]; mode?: TagQueryMode };\n }) => Promise<number>;\n /**\n * Create a job processor. Handlers must be provided per-processor.\n */\n createProcessor: (\n handlers: JobHandlers<PayloadMap>,\n options?: ProcessorOptions,\n ) => Processor;\n\n /**\n * Get the job events for a job.\n */\n getJobEvents: (jobId: number) => Promise<JobEvent[]>;\n /**\n * Get the database pool.\n */\n getPool: () => Pool;\n}\n","import { AsyncLocalStorage } from 'async_hooks';\n\nexport const logStorage = new AsyncLocalStorage<{\n verbose: boolean;\n}>();\n\nexport const setLogContext = (verbose: boolean) => {\n logStorage.enterWith({ verbose });\n};\n\nexport const getLogContext = () => {\n return logStorage.getStore();\n};\n\nexport const log = (message: string) => {\n const context = getLogContext();\n if (context?.verbose) {\n console.log(message);\n }\n};\n","import { Pool } from 'pg';\nimport {\n JobOptions,\n JobRecord,\n FailureReason,\n JobEvent,\n JobEventType,\n TagQueryMode,\n} from './types.js';\nimport { log } from './log-context.js';\n\n/**\n * Record a job event in the job_events table\n */\nexport const recordJobEvent = async (\n pool: Pool,\n jobId: number,\n eventType: JobEventType,\n metadata?: any,\n): Promise<void> => {\n const client = await pool.connect();\n try {\n await client.query(\n `INSERT INTO job_events (job_id, event_type, metadata) VALUES ($1, $2, $3)`,\n [jobId, eventType, metadata ? JSON.stringify(metadata) : null],\n );\n } catch (error) {\n log(`Error recording job event for job ${jobId}: ${error}`);\n // Do not throw, to avoid interfering with main job logic\n } finally {\n client.release();\n }\n};\n\n/**\n * Add a job to the queue\n */\nexport const addJob = async <PayloadMap, T extends keyof PayloadMap & string>(\n pool: Pool,\n {\n jobType,\n payload,\n maxAttempts = 3,\n priority = 0,\n runAt = null,\n timeoutMs = undefined,\n tags = undefined,\n }: JobOptions<PayloadMap, T>,\n): Promise<number> => {\n const client = await pool.connect();\n try {\n let result;\n if (runAt) {\n result = await client.query(\n `INSERT INTO job_queue \n (job_type, payload, max_attempts, priority, run_at, timeout_ms, tags) \n VALUES ($1, $2, $3, $4, $5, $6, $7) \n RETURNING id`,\n [\n jobType,\n payload,\n maxAttempts,\n priority,\n runAt,\n timeoutMs ?? null,\n tags ?? null,\n ],\n );\n log(\n `Added job ${result.rows[0].id}: payload ${JSON.stringify(payload)}, runAt ${runAt.toISOString()}, priority ${priority}, maxAttempts ${maxAttempts} jobType ${jobType}, tags ${JSON.stringify(tags)}`,\n );\n } else {\n result = await client.query(\n `INSERT INTO job_queue \n (job_type, payload, max_attempts, priority, timeout_ms, tags) \n VALUES ($1, $2, $3, $4, $5, $6) \n RETURNING id`,\n [\n jobType,\n payload,\n maxAttempts,\n priority,\n timeoutMs ?? null,\n tags ?? null,\n ],\n );\n log(\n `Added job ${result.rows[0].id}: payload ${JSON.stringify(payload)}, priority ${priority}, maxAttempts ${maxAttempts} jobType ${jobType}, tags ${JSON.stringify(tags)}`,\n );\n }\n await recordJobEvent(pool, result.rows[0].id, JobEventType.Added, {\n jobType,\n payload,\n tags,\n });\n return result.rows[0].id;\n } catch (error) {\n log(`Error adding job: ${error}`);\n throw error;\n } finally {\n client.release();\n }\n};\n\n/**\n * Get a job by ID\n */\nexport const getJob = async <PayloadMap, T extends keyof PayloadMap & string>(\n pool: Pool,\n id: number,\n): Promise<JobRecord<PayloadMap, T> | null> => {\n const client = await pool.connect();\n try {\n const result = await client.query(\n `SELECT id, job_type AS \"jobType\", payload, status, max_attempts AS \"maxAttempts\", attempts, priority, run_at AS \"runAt\", timeout_ms AS \"timeoutMs\", created_at AS \"createdAt\", updated_at AS \"updatedAt\", started_at AS \"startedAt\", completed_at AS \"completedAt\", last_failed_at AS \"lastFailedAt\", locked_at AS \"lockedAt\", locked_by AS \"lockedBy\", error_history AS \"errorHistory\", failure_reason AS \"failureReason\", next_attempt_at AS \"nextAttemptAt\", last_failed_at AS \"lastFailedAt\", last_retried_at AS \"lastRetriedAt\", last_cancelled_at AS \"lastCancelledAt\", pending_reason AS \"pendingReason\" FROM job_queue WHERE id = $1`,\n [id],\n );\n\n if (result.rows.length === 0) {\n log(`Job ${id} not found`);\n return null;\n }\n\n log(`Found job ${id}`);\n\n const job = result.rows[0] as JobRecord<PayloadMap, T>;\n\n return {\n ...job,\n payload: job.payload,\n timeoutMs: job.timeoutMs,\n failureReason: job.failureReason,\n };\n } catch (error) {\n log(`Error getting job ${id}: ${error}`);\n throw error;\n } finally {\n client.release();\n }\n};\n\n/**\n * Get jobs by status\n */\nexport const getJobsByStatus = async <\n PayloadMap,\n T extends keyof PayloadMap & string,\n>(\n pool: Pool,\n status: string,\n limit = 100,\n offset = 0,\n): Promise<JobRecord<PayloadMap, T>[]> => {\n const client = await pool.connect();\n try {\n const result = await client.query(\n `SELECT id, job_type AS \"jobType\", payload, status, max_attempts AS \"maxAttempts\", attempts, priority, run_at AS \"runAt\", timeout_ms AS \"timeoutMs\", created_at AS \"createdAt\", updated_at AS \"updatedAt\", started_at AS \"startedAt\", completed_at AS \"completedAt\", last_failed_at AS \"lastFailedAt\", locked_at AS \"lockedAt\", locked_by AS \"lockedBy\", error_history AS \"errorHistory\", failure_reason AS \"failureReason\", next_attempt_at AS \"nextAttemptAt\", last_failed_at AS \"lastFailedAt\", last_retried_at AS \"lastRetriedAt\", last_cancelled_at AS \"lastCancelledAt\", pending_reason AS \"pendingReason\" FROM job_queue WHERE status = $1 ORDER BY created_at DESC LIMIT $2 OFFSET $3`,\n [status, limit, offset],\n );\n\n log(`Found ${result.rows.length} jobs by status ${status}`);\n\n return result.rows.map((job) => ({\n ...job,\n payload: job.payload,\n timeoutMs: job.timeoutMs,\n failureReason: job.failureReason,\n }));\n } catch (error) {\n log(`Error getting jobs by status ${status}: ${error}`);\n throw error;\n } finally {\n client.release();\n }\n};\n\n/**\n * Get the next batch of jobs to process\n * @param pool - The database pool\n * @param workerId - The worker ID\n * @param batchSize - The batch size\n * @param jobType - Only fetch jobs with this job type (string or array of strings)\n */\nexport const getNextBatch = async <\n PayloadMap,\n T extends keyof PayloadMap & string,\n>(\n pool: Pool,\n workerId: string,\n batchSize = 10,\n jobType?: string | string[],\n): Promise<JobRecord<PayloadMap, T>[]> => {\n const client = await pool.connect();\n try {\n // Begin transaction\n await client.query('BEGIN');\n\n // Build job type filter\n let jobTypeFilter = '';\n let params: any[] = [workerId, batchSize];\n if (jobType) {\n if (Array.isArray(jobType)) {\n jobTypeFilter = ` AND job_type = ANY($3)`;\n params.push(jobType);\n } else {\n jobTypeFilter = ` AND job_type = $3`;\n params.push(jobType);\n }\n }\n\n // Get and lock a batch of jobs\n const result = await client.query(\n `\n UPDATE job_queue\n SET status = 'processing', \n locked_at = NOW(), \n locked_by = $1,\n attempts = attempts + 1,\n updated_at = NOW(),\n pending_reason = NULL,\n started_at = COALESCE(started_at, NOW()),\n last_retried_at = CASE WHEN attempts > 0 THEN NOW() ELSE last_retried_at END\n WHERE id IN (\n SELECT id FROM job_queue\n WHERE (status = 'pending' OR (status = 'failed' AND next_attempt_at <= NOW()))\n AND (attempts < max_attempts)\n AND run_at <= NOW()\n ${jobTypeFilter}\n ORDER BY priority DESC, created_at ASC\n LIMIT $2\n FOR UPDATE SKIP LOCKED\n )\n RETURNING id, job_type AS \"jobType\", payload, status, max_attempts AS \"maxAttempts\", attempts, priority, run_at AS \"runAt\", timeout_ms AS \"timeoutMs\", created_at AS \"createdAt\", updated_at AS \"updatedAt\", started_at AS \"startedAt\", completed_at AS \"completedAt\", last_failed_at AS \"lastFailedAt\", locked_at AS \"lockedAt\", locked_by AS \"lockedBy\", error_history AS \"errorHistory\", failure_reason AS \"failureReason\", next_attempt_at AS \"nextAttemptAt\", last_retried_at AS \"lastRetriedAt\", last_cancelled_at AS \"lastCancelledAt\", pending_reason AS \"pendingReason\"\n `,\n params,\n );\n\n log(`Found ${result.rows.length} jobs to process`);\n\n // Commit transaction\n await client.query('COMMIT');\n\n // Record processing event for each job\n for (const row of result.rows) {\n await recordJobEvent(pool, row.id, JobEventType.Processing);\n }\n\n return result.rows.map((job) => ({\n ...job,\n payload: job.payload,\n timeoutMs: job.timeoutMs,\n }));\n } catch (error) {\n log(`Error getting next batch: ${error}`);\n await client.query('ROLLBACK');\n throw error;\n } finally {\n client.release();\n }\n};\n\n/**\n * Mark a job as completed\n */\nexport const completeJob = async (pool: Pool, jobId: number): Promise<void> => {\n const client = await pool.connect();\n try {\n await client.query(\n `\n UPDATE job_queue\n SET status = 'completed', updated_at = NOW(), completed_at = NOW()\n WHERE id = $1\n `,\n [jobId],\n );\n await recordJobEvent(pool, jobId, JobEventType.Completed);\n } catch (error) {\n log(`Error completing job ${jobId}: ${error}`);\n throw error;\n } finally {\n log(`Completed job ${jobId}`);\n client.release();\n }\n};\n\n/**\n * Mark a job as failed\n */\nexport const failJob = async (\n pool: Pool,\n jobId: number,\n error: Error,\n failureReason?: FailureReason,\n): Promise<void> => {\n const client = await pool.connect();\n try {\n /**\n * The next attempt will be scheduled after `2^attempts * 1 minute` from the last attempt.\n */\n await client.query(\n `\n UPDATE job_queue\n SET status = 'failed', \n updated_at = NOW(),\n next_attempt_at = CASE \n WHEN attempts < max_attempts THEN NOW() + (POWER(2, attempts) * INTERVAL '1 minute')\n ELSE NULL\n END,\n error_history = COALESCE(error_history, '[]'::jsonb) || $2::jsonb,\n failure_reason = $3,\n last_failed_at = NOW()\n WHERE id = $1\n `,\n [\n jobId,\n JSON.stringify([\n {\n message: error.message || String(error),\n timestamp: new Date().toISOString(),\n },\n ]),\n failureReason ?? null,\n ],\n );\n await recordJobEvent(pool, jobId, JobEventType.Failed, {\n message: error.message || String(error),\n failureReason,\n });\n } catch (error) {\n log(`Error failing job ${jobId}: ${error}`);\n throw error;\n } finally {\n log(`Failed job ${jobId}`);\n client.release();\n }\n};\n\n/**\n * Retry a failed job immediately\n */\nexport const retryJob = async (pool: Pool, jobId: number): Promise<void> => {\n const client = await pool.connect();\n try {\n await client.query(\n `\n UPDATE job_queue\n SET status = 'pending', \n updated_at = NOW(),\n locked_at = NULL,\n locked_by = NULL,\n next_attempt_at = NOW(),\n last_retried_at = NOW()\n WHERE id = $1\n `,\n [jobId],\n );\n await recordJobEvent(pool, jobId, JobEventType.Retried);\n } catch (error) {\n log(`Error retrying job ${jobId}: ${error}`);\n throw error;\n } finally {\n log(`Retried job ${jobId}`);\n client.release();\n }\n};\n\n/**\n * Delete old completed jobs\n */\nexport const cleanupOldJobs = async (\n pool: Pool,\n daysToKeep = 30,\n): Promise<number> => {\n const client = await pool.connect();\n try {\n const result = await client.query(`\n DELETE FROM job_queue\n WHERE status = 'completed'\n AND updated_at < NOW() - INTERVAL '${daysToKeep} days'\n RETURNING id\n `);\n log(`Deleted ${result.rowCount} old jobs`);\n return result.rowCount || 0;\n } catch (error) {\n log(`Error cleaning up old jobs: ${error}`);\n throw error;\n } finally {\n client.release();\n }\n};\n\n/**\n * Cancel a scheduled job (only if still pending)\n */\nexport const cancelJob = async (pool: Pool, jobId: number): Promise<void> => {\n const client = await pool.connect();\n try {\n await client.query(\n `\n UPDATE job_queue\n SET status = 'cancelled', updated_at = NOW(), last_cancelled_at = NOW()\n WHERE id = $1 AND status = 'pending'\n `,\n [jobId],\n );\n await recordJobEvent(pool, jobId, JobEventType.Cancelled);\n } catch (error) {\n log(`Error cancelling job ${jobId}: ${error}`);\n throw error;\n } finally {\n log(`Cancelled job ${jobId}`);\n client.release();\n }\n};\n\n/**\n * Cancel all upcoming jobs (pending and scheduled in the future) with optional filters\n */\nexport const cancelAllUpcomingJobs = async (\n pool: Pool,\n filters?: {\n jobType?: string;\n priority?: number;\n runAt?: Date | { gt?: Date; gte?: Date; lt?: Date; lte?: Date; eq?: Date };\n tags?: { values: string[]; mode?: TagQueryMode };\n },\n): Promise<number> => {\n const client = await pool.connect();\n try {\n let query = `\n UPDATE job_queue\n SET status = 'cancelled', updated_at = NOW()\n WHERE status = 'pending'`;\n const params: any[] = [];\n let paramIdx = 1;\n if (filters) {\n if (filters.jobType) {\n query += ` AND job_type = $${paramIdx++}`;\n params.push(filters.jobType);\n }\n if (filters.priority !== undefined) {\n query += ` AND priority = $${paramIdx++}`;\n params.push(filters.priority);\n }\n if (filters.runAt) {\n if (filters.runAt instanceof Date) {\n query += ` AND run_at = $${paramIdx++}`;\n params.push(filters.runAt);\n } else if (typeof filters.runAt === 'object') {\n const ops = filters.runAt;\n if (ops.gt) {\n query += ` AND run_at > $${paramIdx++}`;\n params.push(ops.gt);\n }\n if (ops.gte) {\n query += ` AND run_at >= $${paramIdx++}`;\n params.push(ops.gte);\n }\n if (ops.lt) {\n query += ` AND run_at < $${paramIdx++}`;\n params.push(ops.lt);\n }\n if (ops.lte) {\n query += ` AND run_at <= $${paramIdx++}`;\n params.push(ops.lte);\n }\n if (ops.eq) {\n query += ` AND run_at = $${paramIdx++}`;\n params.push(ops.eq);\n }\n }\n }\n if (\n filters.tags &&\n filters.tags.values &&\n filters.tags.values.length > 0\n ) {\n const mode = filters.tags.mode || 'all';\n const tagValues = filters.tags.values;\n switch (mode) {\n case 'exact':\n query += ` AND tags = $${paramIdx++}`;\n params.push(tagValues);\n break;\n case 'all':\n query += ` AND tags @> $${paramIdx++}`;\n params.push(tagValues);\n break;\n case 'any':\n query += ` AND tags && $${paramIdx++}`;\n params.push(tagValues);\n break;\n case 'none':\n query += ` AND NOT (tags && $${paramIdx++})`;\n params.push(tagValues);\n break;\n default:\n query += ` AND tags @> $${paramIdx++}`;\n params.push(tagValues);\n }\n }\n }\n query += '\\nRETURNING id';\n const result = await client.query(query, params);\n log(`Cancelled ${result.rowCount} jobs`);\n return result.rowCount || 0;\n } catch (error) {\n log(`Error cancelling upcoming jobs: ${error}`);\n throw error;\n } finally {\n client.release();\n }\n};\n\n/**\n * Get all jobs with optional pagination\n */\nexport const getAllJobs = async <\n PayloadMap,\n T extends keyof PayloadMap & string,\n>(\n pool: Pool,\n limit = 100,\n offset = 0,\n): Promise<JobRecord<PayloadMap, T>[]> => {\n const client = await pool.connect();\n try {\n const result = await client.query(\n `SELECT id, job_type AS \"jobType\", payload, status, max_attempts AS \"maxAttempts\", attempts, priority, run_at AS \"runAt\", timeout_ms AS \"timeoutMs\", created_at AS \"createdAt\", updated_at AS \"updatedAt\", started_at AS \"startedAt\", completed_at AS \"completedAt\", last_failed_at AS \"lastFailedAt\", locked_at AS \"lockedAt\", locked_by AS \"lockedBy\", error_history AS \"errorHistory\", failure_reason AS \"failureReason\", next_attempt_at AS \"nextAttemptAt\", last_failed_at AS \"lastFailedAt\", last_retried_at AS \"lastRetriedAt\", last_cancelled_at AS \"lastCancelledAt\", pending_reason AS \"pendingReason\" FROM job_queue ORDER BY created_at DESC LIMIT $1 OFFSET $2`,\n [limit, offset],\n );\n log(`Found ${result.rows.length} jobs (all)`);\n return result.rows.map((job) => ({\n ...job,\n payload: job.payload,\n timeoutMs: job.timeoutMs,\n }));\n } catch (error) {\n log(`Error getting all jobs: ${error}`);\n throw error;\n } finally {\n client.release();\n }\n};\n\n/**\n * Set a pending reason for unpicked jobs\n */\nexport const setPendingReasonForUnpickedJobs = async (\n pool: Pool,\n reason: string,\n jobType?: string | string[],\n) => {\n const client = await pool.connect();\n try {\n let jobTypeFilter = '';\n let params: any[] = [reason];\n if (jobType) {\n if (Array.isArray(jobType)) {\n jobTypeFilter = ` AND job_type = ANY($2)`;\n params.push(jobType);\n } else {\n jobTypeFilter = ` AND job_type = $2`;\n params.push(jobType);\n }\n }\n await client.query(\n `UPDATE job_queue SET pending_reason = $1 WHERE status = 'pending'${jobTypeFilter}`,\n params,\n );\n } finally {\n client.release();\n }\n};\n\n/**\n * Reclaim jobs stuck in 'processing' for too long.\n *\n * If a process (e.g., API route or worker) crashes after marking a job as 'processing' but before completing it, the job can remain stuck in the 'processing' state indefinitely. This can happen if the process is killed or encounters an unhandled error after updating the job status but before marking it as 'completed' or 'failed'.\n * @param pool - The database pool\n * @param maxProcessingTimeMinutes - Max allowed processing time in minutes (default: 10)\n * @returns Number of jobs reclaimed\n */\nexport const reclaimStuckJobs = async (\n pool: Pool,\n maxProcessingTimeMinutes = 10,\n): Promise<number> => {\n const client = await pool.connect();\n try {\n const result = await client.query(\n `\n UPDATE job_queue\n SET status = 'pending', locked_at = NULL, locked_by = NULL, updated_at = NOW()\n WHERE status = 'processing'\n AND locked_at < NOW() - INTERVAL '${maxProcessingTimeMinutes} minutes'\n RETURNING id\n `,\n );\n log(`Reclaimed ${result.rowCount} stuck jobs`);\n return result.rowCount || 0;\n } catch (error) {\n log(`Error reclaiming stuck jobs: ${error}`);\n throw error;\n } finally {\n client.release();\n }\n};\n\n/**\n * Get all events for a job, ordered by createdAt ascending\n */\nexport const getJobEvents = async (\n pool: Pool,\n jobId: number,\n): Promise<JobEvent[]> => {\n const client = await pool.connect();\n try {\n const res = await client.query(\n `SELECT id, job_id AS \"jobId\", event_type AS \"eventType\", metadata, created_at AS \"createdAt\" FROM job_events WHERE job_id = $1 ORDER BY created_at ASC`,\n [jobId],\n );\n return res.rows as JobEvent[];\n } finally {\n client.release();\n }\n};\n\n/**\n * Get jobs by tags (matches all specified tags)\n */\nexport const getJobsByTags = async <\n PayloadMap,\n T extends keyof PayloadMap & string,\n>(\n pool: Pool,\n tags: string[],\n mode: TagQueryMode = 'all',\n limit = 100,\n offset = 0,\n): Promise<JobRecord<PayloadMap, T>[]> => {\n const client = await pool.connect();\n try {\n let query = `SELECT id, job_type AS \"jobType\", payload, status, max_attempts AS \"maxAttempts\", attempts, priority, run_at AS \"runAt\", timeout_ms AS \"timeoutMs\", created_at AS \"createdAt\", updated_at AS \"updatedAt\", started_at AS \"startedAt\", completed_at AS \"completedAt\", last_failed_at AS \"lastFailedAt\", locked_at AS \"lockedAt\", locked_by AS \"lockedBy\", error_history AS \"errorHistory\", failure_reason AS \"failureReason\", next_attempt_at AS \"nextAttemptAt\", last_failed_at AS \"lastFailedAt\", last_retried_at AS \"lastRetriedAt\", last_cancelled_at AS \"lastCancelledAt\", pending_reason AS \"pendingReason\", tags\n FROM job_queue`;\n let params: any[] = [];\n switch (mode) {\n case 'exact':\n query += ' WHERE tags = $1';\n params = [tags];\n break;\n case 'all':\n query += ' WHERE tags @> $1';\n params = [tags];\n break;\n case 'any':\n query += ' WHERE tags && $1';\n params = [tags];\n break;\n case 'none':\n query += ' WHERE NOT (tags && $1)';\n params = [tags];\n break;\n default:\n query += ' WHERE tags @> $1';\n params = [tags];\n }\n query += ' ORDER BY created_at DESC LIMIT $2 OFFSET $3';\n params.push(limit, offset);\n const result = await client.query(query, params);\n log(\n `Found ${result.rows.length} jobs by tags ${JSON.stringify(tags)} (mode: ${mode})`,\n );\n return result.rows.map((job) => ({\n ...job,\n payload: job.payload,\n timeoutMs: job.timeoutMs,\n failureReason: job.failureReason,\n }));\n } catch (error) {\n log(\n `Error getting jobs by tags ${JSON.stringify(tags)} (mode: ${mode}): ${error}`,\n );\n throw error;\n } finally {\n client.release();\n }\n};\n\nexport const getJobs = async <PayloadMap, T extends keyof PayloadMap & string>(\n pool: Pool,\n filters?: {\n jobType?: string;\n priority?: number;\n runAt?: Date | { gt?: Date; gte?: Date; lt?: Date; lte?: Date; eq?: Date };\n tags?: { values: string[]; mode?: TagQueryMode };\n },\n limit = 100,\n offset = 0,\n): Promise<JobRecord<PayloadMap, T>[]> => {\n const client = await pool.connect();\n try {\n let query = `SELECT id, job_type AS \"jobType\", payload, status, max_attempts AS \"maxAttempts\", attempts, priority, run_at AS \"runAt\", timeout_ms AS \"timeoutMs\", created_at AS \"createdAt\", updated_at AS \"updatedAt\", started_at AS \"startedAt\", completed_at AS \"completedAt\", last_failed_at AS \"lastFailedAt\", locked_at AS \"lockedAt\", locked_by AS \"lockedBy\", error_history AS \"errorHistory\", failure_reason AS \"failureReason\", next_attempt_at AS \"nextAttemptAt\", last_failed_at AS \"lastFailedAt\", last_retried_at AS \"lastRetriedAt\", last_cancelled_at AS \"lastCancelledAt\", pending_reason AS \"pendingReason\", tags FROM job_queue`;\n const params: any[] = [];\n let where: string[] = [];\n let paramIdx = 1;\n if (filters) {\n if (filters.jobType) {\n where.push(`job_type = $${paramIdx++}`);\n params.push(filters.jobType);\n }\n if (filters.priority !== undefined) {\n where.push(`priority = $${paramIdx++}`);\n params.push(filters.priority);\n }\n if (filters.runAt) {\n if (filters.runAt instanceof Date) {\n where.push(`run_at = $${paramIdx++}`);\n params.push(filters.runAt);\n } else if (\n typeof filters.runAt === 'object' &&\n (filters.runAt.gt !== undefined ||\n filters.runAt.gte !== undefined ||\n filters.runAt.lt !== undefined ||\n filters.runAt.lte !== undefined ||\n filters.runAt.eq !== undefined)\n ) {\n const ops = filters.runAt as {\n gt?: Date;\n gte?: Date;\n lt?: Date;\n lte?: Date;\n eq?: Date;\n };\n if (ops.gt) {\n where.push(`run_at > $${paramIdx++}`);\n params.push(ops.gt);\n }\n if (ops.gte) {\n where.push(`run_at >= $${paramIdx++}`);\n params.push(ops.gte);\n }\n if (ops.lt) {\n where.push(`run_at < $${paramIdx++}`);\n params.push(ops.lt);\n }\n if (ops.lte) {\n where.push(`run_at <= $${paramIdx++}`);\n params.push(ops.lte);\n }\n if (ops.eq) {\n where.push(`run_at = $${paramIdx++}`);\n params.push(ops.eq);\n }\n }\n }\n if (\n filters.tags &&\n filters.tags.values &&\n filters.tags.values.length > 0\n ) {\n const mode = filters.tags.mode || 'all';\n const tagValues = filters.tags.values;\n switch (mode) {\n case 'exact':\n where.push(`tags = $${paramIdx++}`);\n params.push(tagValues);\n break;\n case 'all':\n where.push(`tags @> $${paramIdx++}`);\n params.push(tagValues);\n break;\n case 'any':\n where.push(`tags && $${paramIdx++}`);\n params.push(tagValues);\n break;\n case 'none':\n where.push(`NOT (tags && $${paramIdx++})`);\n params.push(tagValues);\n break;\n default:\n where.push(`tags @> $${paramIdx++}`);\n params.push(tagValues);\n }\n }\n }\n if (where.length > 0) {\n query += ` WHERE ${where.join(' AND ')}`;\n }\n // Always add LIMIT and OFFSET as the last parameters\n paramIdx = params.length + 1;\n query += ` ORDER BY created_at DESC LIMIT $${paramIdx++} OFFSET $${paramIdx}`;\n params.push(limit, offset);\n const result = await client.query(query, params);\n log(`Found ${result.rows.length} jobs`);\n return result.rows.map((job) => ({\n ...job,\n payload: job.payload,\n timeoutMs: job.timeoutMs,\n failureReason: job.failureReason,\n }));\n } catch (error) {\n log(`Error getting jobs: ${error}`);\n throw error;\n } finally {\n client.release();\n }\n};\n","import { Pool } from 'pg';\nimport {\n JobRecord,\n ProcessorOptions,\n Processor,\n JobHandler,\n JobType,\n FailureReason,\n JobHandlers,\n} from './types.js';\nimport {\n getNextBatch,\n completeJob,\n failJob,\n setPendingReasonForUnpickedJobs,\n} from './queue.js';\nimport { log, setLogContext } from './log-context.js';\n\n/**\n * Process a single job using the provided handler map\n */\nexport async function processJobWithHandlers<\n PayloadMap,\n T extends keyof PayloadMap & string,\n>(\n pool: Pool,\n job: JobRecord<PayloadMap, T>,\n jobHandlers: JobHandlers<PayloadMap>,\n): Promise<void> {\n const handler = jobHandlers[job.jobType];\n\n if (!handler) {\n await setPendingReasonForUnpickedJobs(\n pool,\n `No handler registered for job type: ${job.jobType}`,\n job.jobType,\n );\n await failJob(\n pool,\n job.id,\n new Error(`No handler registered for job type: ${job.jobType}`),\n FailureReason.NoHandler,\n );\n return;\n }\n\n // Per-job timeout logic\n const timeoutMs = job.timeoutMs ?? undefined;\n let timeoutId: NodeJS.Timeout | undefined;\n const controller = new AbortController();\n try {\n const jobPromise = handler(job.payload, controller.signal);\n if (timeoutMs && timeoutMs > 0) {\n await Promise.race([\n jobPromise,\n new Promise((_, reject) => {\n timeoutId = setTimeout(() => {\n controller.abort();\n const timeoutError = new Error(\n `Job timed out after ${timeoutMs} ms`,\n );\n // @ts-ignore\n timeoutError.failureReason = FailureReason.Timeout;\n reject(timeoutError);\n }, timeoutMs);\n }),\n ]);\n } else {\n await jobPromise;\n }\n if (timeoutId) clearTimeout(timeoutId);\n await completeJob(pool, job.id);\n } catch (error) {\n if (timeoutId) clearTimeout(timeoutId);\n console.error(`Error processing job ${job.id}:`, error);\n let failureReason = FailureReason.HandlerError;\n if (\n error &&\n typeof error === 'object' &&\n 'failureReason' in error &&\n (error as any).failureReason === FailureReason.Timeout\n ) {\n failureReason = FailureReason.Timeout;\n }\n await failJob(\n pool,\n job.id,\n error instanceof Error ? error : new Error(String(error)),\n failureReason,\n );\n }\n}\n\n/**\n * Process a batch of jobs using the provided handler map and concurrency limit\n */\nexport async function processBatchWithHandlers<PayloadMap>(\n pool: Pool,\n workerId: string,\n batchSize: number,\n jobType: string | string[] | undefined,\n jobHandlers: JobHandlers<PayloadMap>,\n concurrency?: number,\n): Promise<number> {\n const jobs = await getNextBatch<PayloadMap, JobType<PayloadMap>>(\n pool,\n workerId,\n batchSize,\n jobType,\n );\n if (!concurrency || concurrency >= jobs.length) {\n // Default: all in parallel\n await Promise.all(\n jobs.map((job) => processJobWithHandlers(pool, job, jobHandlers)),\n );\n return jobs.length;\n }\n // Concurrency-limited pool\n let idx = 0;\n let running = 0;\n let finished = 0;\n return new Promise((resolve, reject) => {\n const next = () => {\n if (finished === jobs.length) return resolve(jobs.length);\n while (running < concurrency && idx < jobs.length) {\n const job = jobs[idx++];\n running++;\n processJobWithHandlers(pool, job, jobHandlers)\n .then(() => {\n running--;\n finished++;\n next();\n })\n .catch((err) => {\n running--;\n finished++;\n next();\n });\n }\n };\n next();\n });\n}\n\n/**\n * Start a job processor that continuously processes jobs\n * @param pool - The database pool\n * @param handlers - The job handlers for this processor instance\n * @param options - The processor options. Leave pollInterval empty to run only once. Use jobType to filter jobs by type.\n * @returns {Processor} The processor instance\n */\nexport const createProcessor = <PayloadMap = any>(\n pool: Pool,\n handlers: JobHandlers<PayloadMap>,\n options: ProcessorOptions = {},\n): Processor => {\n const {\n workerId = `worker-${Math.random().toString(36).substring(2, 9)}`,\n batchSize = 10,\n pollInterval = 5000,\n onError = (error: Error) => console.error('Job processor error:', error),\n jobType,\n concurrency = 3,\n } = options;\n\n let running = false;\n let intervalId: NodeJS.Timeout | null = null;\n\n setLogContext(options.verbose ?? false);\n\n const processJobs = async (): Promise<number> => {\n if (!running) return 0;\n\n log(\n `Processing jobs with workerId: ${workerId}${jobType ? ` and jobType: ${Array.isArray(jobType) ? jobType.join(',') : jobType}` : ''}`,\n );\n\n try {\n const processed = await processBatchWithHandlers(\n pool,\n workerId,\n batchSize,\n jobType,\n handlers,\n concurrency,\n );\n // Only process one batch in start; do not schedule next batch here\n return processed;\n } catch (error) {\n onError(error instanceof Error ? error : new Error(String(error)));\n }\n return 0;\n };\n\n return {\n /**\n * Start the job processor in the background.\n * - This will run periodically (every pollInterval milliseconds or 5 seconds if not provided) and process jobs as they become available.\n * - You have to call the stop method to stop the processor.\n */\n startInBackground: () => {\n if (running) return;\n\n log(`Starting job processor with workerId: ${workerId}`);\n running = true;\n // Background: process batches repeatedly if needed\n const processBatches = async () => {\n if (!running) return;\n const processed = await processJobs();\n if (processed === batchSize && running) {\n setImmediate(processBatches);\n }\n };\n processBatches(); // Process immediately on start\n intervalId = setInterval(processJobs, pollInterval);\n },\n /**\n * Stop the job processor that runs in the background\n */\n stop: () => {\n log(`Stopping job processor with workerId: ${workerId}`);\n running = false;\n if (intervalId) {\n clearInterval(intervalId);\n intervalId = null;\n }\n },\n /**\n * Start the job processor synchronously.\n * - This will process all jobs immediately and then stop.\n * - The pollInterval is ignored.\n */\n start: async () => {\n log(`Starting job processor with workerId: ${workerId}`);\n running = true;\n const processed = await processJobs();\n running = false;\n return processed;\n },\n isRunning: () => running,\n };\n};\n","import { Pool } from 'pg';\nimport { JobQueueConfig } from './types.js';\nimport { parse } from 'pg-connection-string';\nimport fs from 'fs';\n\n/**\n * Helper to load a PEM string or file. Only values starting with 'file://' are loaded from file.\n */\nfunction loadPemOrFile(value?: string): string | undefined {\n if (!value) return undefined;\n if (value.startsWith('file://')) {\n const filePath = value.slice(7);\n return fs.readFileSync(filePath, 'utf8');\n }\n return value;\n}\n\n/**\n * Create a database connection pool with flexible SSL certificate loading.\n *\n * SSL config example (for local file paths):\n * ssl: {\n * ca: process.env.PGSSLROOTCERT, // PEM string or 'file://...'\n * cert: process.env.PGSSLCERT, // optional, PEM string or 'file://...'\n * key: process.env.PGSSLKEY, // optional, PEM string or 'file://...'\n * rejectUnauthorized: true\n * }\n */\nexport const createPool = (config: JobQueueConfig['databaseConfig']): Pool => {\n let searchPath: string | undefined;\n let ssl: any = undefined;\n let customCA: string | undefined;\n let sslmode: string | undefined;\n\n if (config.connectionString) {\n try {\n const url = new URL(config.connectionString);\n searchPath = url.searchParams.get('search_path') || undefined;\n sslmode = url.searchParams.get('sslmode') || undefined;\n if (sslmode === 'no-verify') {\n ssl = { rejectUnauthorized: false };\n }\n } catch (e) {\n const parsed = parse(config.connectionString);\n if (parsed.options) {\n const match = parsed.options.match(/search_path=([^\\s]+)/);\n if (match) {\n searchPath = match[1];\n }\n }\n sslmode = typeof parsed.sslmode === 'string' ? parsed.sslmode : undefined;\n if (sslmode === 'no-verify') {\n ssl = { rejectUnauthorized: false };\n }\n }\n }\n\n // Flexible SSL loading: only support file:// for file loading\n if (config.ssl) {\n if (typeof config.ssl.ca === 'string') {\n customCA = config.ssl.ca;\n } else if (typeof process.env.PGSSLROOTCERT === 'string') {\n customCA = process.env.PGSSLROOTCERT;\n } else {\n customCA = undefined;\n }\n const caValue =\n typeof customCA === 'string' ? loadPemOrFile(customCA) : undefined;\n ssl = {\n ...ssl,\n ...(caValue ? { ca: caValue } : {}),\n cert: loadPemOrFile(\n typeof config.ssl.cert === 'string'\n ? config.ssl.cert\n : process.env.PGSSLCERT,\n ),\n key: loadPemOrFile(\n typeof config.ssl.key === 'string'\n ? config.ssl.key\n : process.env.PGSSLKEY,\n ),\n rejectUnauthorized:\n config.ssl.rejectUnauthorized !== undefined\n ? config.ssl.rejectUnauthorized\n : true,\n };\n }\n\n // Warn if both sslmode (any value) and a custom CA are set\n if (sslmode && customCA) {\n const warning = `\\n\\n\\x1b[33m**************************************************\\n\\u26A0\\uFE0F WARNING: SSL CONFIGURATION ISSUE\\n**************************************************\\nBoth sslmode ('${sslmode}') is set in the connection string\\nand a custom CA is provided (via config.ssl.ca or PGSSLROOTCERT).\\nThis combination may cause connection failures or unexpected behavior.\\n\\nRecommended: Remove sslmode from the connection string when using a custom CA.\\n**************************************************\\x1b[0m\\n`;\n console.warn(warning);\n }\n\n const pool = new Pool({\n ...config,\n ...(ssl ? { ssl } : {}),\n });\n\n if (searchPath) {\n pool.on('connect', (client) => {\n client.query(`SET search_path TO ${searchPath}`);\n });\n }\n\n return pool;\n};\n","import {\n addJob,\n getJob,\n getJobsByStatus,\n retryJob,\n cleanupOldJobs,\n cancelJob,\n cancelAllUpcomingJobs,\n getAllJobs,\n reclaimStuckJobs,\n getJobEvents,\n getJobsByTags,\n getJobs,\n} from './queue.js';\nimport { createProcessor } from './processor.js';\nimport {\n JobQueueConfig,\n JobQueue,\n JobOptions,\n ProcessorOptions,\n JobHandlers,\n} from './types.js';\nimport { setLogContext } from './log-context.js';\nimport { createPool } from './db-util.js';\n\n/**\n * Initialize the job queue system\n */\nexport const initJobQueue = <PayloadMap = any>(\n config: JobQueueConfig,\n): JobQueue<PayloadMap> => {\n const { databaseConfig } = config;\n\n // Create database pool\n const pool = createPool(databaseConfig);\n\n setLogContext(config.verbose ?? false);\n\n // Return the job queue API\n return {\n // Job queue operations\n addJob: withLogContext(\n (job: JobOptions<PayloadMap, any>) => addJob<PayloadMap, any>(pool, job),\n config.verbose ?? false,\n ),\n getJob: withLogContext(\n (id: number) => getJob<PayloadMap, any>(pool, id),\n config.verbose ?? false,\n ),\n getJobsByStatus: withLogContext(\n (status: string, limit?: number, offset?: number) =>\n getJobsByStatus<PayloadMap, any>(pool, status, limit, offset),\n config.verbose ?? false,\n ),\n getAllJobs: withLogContext(\n (limit?: number, offset?: number) =>\n getAllJobs<PayloadMap, any>(pool, limit, offset),\n config.verbose ?? false,\n ),\n getJobs: withLogContext(\n (\n filters?: {\n jobType?: string;\n priority?: number;\n runAt?:\n | Date\n | { gt?: Date; gte?: Date; lt?: Date; lte?: Date; eq?: Date };\n tags?: { values: string[]; mode?: import('./types.js').TagQueryMode };\n },\n limit?: number,\n offset?: number,\n ) => getJobs<PayloadMap, any>(pool, filters, limit, offset),\n config.verbose ?? false,\n ),\n retryJob: (jobId: number) => retryJob(pool, jobId),\n cleanupOldJobs: (daysToKeep?: number) => cleanupOldJobs(pool, daysToKeep),\n cancelJob: withLogContext(\n (jobId: number) => cancelJob(pool, jobId),\n config.verbose ?? false,\n ),\n cancelAllUpcomingJobs: withLogContext(\n (filters?: {\n jobType?: string;\n priority?: number;\n runAt?:\n | Date\n | { gt?: Date; gte?: Date; lt?: Date; lte?: Date; eq?: Date };\n tags?: { values: string[]; mode?: import('./types.js').TagQueryMode };\n }) => cancelAllUpcomingJobs(pool, filters),\n config.verbose ?? false,\n ),\n reclaimStuckJobs: withLogContext(\n (maxProcessingTimeMinutes?: number) =>\n reclaimStuckJobs(pool, maxProcessingTimeMinutes),\n config.verbose ?? false,\n ),\n getJobsByTags: withLogContext(\n (tags: string[], mode = 'all', limit?: number, offset?: number) =>\n getJobsByTags<PayloadMap, any>(pool, tags, mode, limit, offset),\n config.verbose ?? false,\n ),\n\n // Job processing\n createProcessor: (\n handlers: JobHandlers<PayloadMap>,\n options?: ProcessorOptions,\n ) => createProcessor<PayloadMap>(pool, handlers, options),\n // Advanced access (for custom operations)\n getPool: () => pool,\n // Job events\n getJobEvents: withLogContext(\n (jobId: number) => getJobEvents(pool, jobId),\n config.verbose ?? false,\n ),\n };\n};\n\nconst withLogContext =\n <T>(fn: (...args: any[]) => T, verbose: boolean) =>\n (...args: Parameters<typeof fn>): ReturnType<typeof fn> => {\n setLogContext(verbose);\n return fn(...args);\n };\n\nexport * from './types.js';\n"]}
package/dist/index.d.cts CHANGED
@@ -147,6 +147,24 @@ interface Processor {
147
147
  */
148
148
  start: () => Promise<number>;
149
149
  }
150
+ interface DatabaseSSLConfig {
151
+ /**
152
+ * CA certificate as PEM string or file path. If the value starts with 'file://', it will be loaded from file, otherwise treated as PEM string.
153
+ */
154
+ ca?: string;
155
+ /**
156
+ * Client certificate as PEM string or file path. If the value starts with 'file://', it will be loaded from file, otherwise treated as PEM string.
157
+ */
158
+ cert?: string;
159
+ /**
160
+ * Client private key as PEM string or file path. If the value starts with 'file://', it will be loaded from file, otherwise treated as PEM string.
161
+ */
162
+ key?: string;
163
+ /**
164
+ * Whether to reject unauthorized certificates (default: true)
165
+ */
166
+ rejectUnauthorized?: boolean;
167
+ }
150
168
  interface JobQueueConfig {
151
169
  databaseConfig: {
152
170
  connectionString?: string;
@@ -155,7 +173,7 @@ interface JobQueueConfig {
155
173
  database?: string;
156
174
  user?: string;
157
175
  password?: string;
158
- ssl?: any;
176
+ ssl?: DatabaseSSLConfig;
159
177
  };
160
178
  verbose?: boolean;
161
179
  }
@@ -190,6 +208,26 @@ interface JobQueue<PayloadMap> {
190
208
  * Get all jobs.
191
209
  */
192
210
  getAllJobs: <T extends JobType<PayloadMap>>(limit?: number, offset?: number) => Promise<JobRecord<PayloadMap, T>[]>;
211
+ /**
212
+ * Get jobs by filters.
213
+ /**
214
+ * Get jobs by filters.
215
+ */
216
+ getJobs: <T extends JobType<PayloadMap>>(filters?: {
217
+ jobType?: string;
218
+ priority?: number;
219
+ runAt?: Date | {
220
+ gt?: Date;
221
+ gte?: Date;
222
+ lt?: Date;
223
+ lte?: Date;
224
+ eq?: Date;
225
+ };
226
+ tags?: {
227
+ values: string[];
228
+ mode?: TagQueryMode;
229
+ };
230
+ }) => Promise<JobRecord<PayloadMap, T>[]>;
193
231
  /**
194
232
  * Retry a job given its ID.
195
233
  * - This will set the job status back to 'pending', clear the locked_at and locked_by, and allow it to be picked up by other workers.
@@ -218,13 +256,19 @@ interface JobQueue<PayloadMap> {
218
256
  * - The filters are:
219
257
  * - jobType: The job type to cancel.
220
258
  * - priority: The priority of the job to cancel.
221
- * - runAt: The time the job is scheduled to run at.
259
+ * - runAt: The time the job is scheduled to run at (now supports gt/gte/lt/lte/eq).
222
260
  * - tags: An object with 'values' (string[]) and 'mode' (TagQueryMode) for tag-based cancellation.
223
261
  */
224
262
  cancelAllUpcomingJobs: (filters?: {
225
263
  jobType?: string;
226
264
  priority?: number;
227
- runAt?: Date;
265
+ runAt?: Date | {
266
+ gt?: Date;
267
+ gte?: Date;
268
+ lt?: Date;
269
+ lte?: Date;
270
+ eq?: Date;
271
+ };
228
272
  tags?: {
229
273
  values: string[];
230
274
  mode?: TagQueryMode;
@@ -249,4 +293,4 @@ interface JobQueue<PayloadMap> {
249
293
  */
250
294
  declare const initJobQueue: <PayloadMap = any>(config: JobQueueConfig) => JobQueue<PayloadMap>;
251
295
 
252
- export { FailureReason, type JobEvent, JobEventType, type JobHandler, type JobHandlers, type JobOptions, type JobQueue, type JobQueueConfig, type JobRecord, type JobStatus, type JobType, type Processor, type ProcessorOptions, type TagQueryMode, initJobQueue };
296
+ export { type DatabaseSSLConfig, FailureReason, type JobEvent, JobEventType, type JobHandler, type JobHandlers, type JobOptions, type JobQueue, type JobQueueConfig, type JobRecord, type JobStatus, type JobType, type Processor, type ProcessorOptions, type TagQueryMode, initJobQueue };
package/dist/index.d.ts CHANGED
@@ -147,6 +147,24 @@ interface Processor {
147
147
  */
148
148
  start: () => Promise<number>;
149
149
  }
150
+ interface DatabaseSSLConfig {
151
+ /**
152
+ * CA certificate as PEM string or file path. If the value starts with 'file://', it will be loaded from file, otherwise treated as PEM string.
153
+ */
154
+ ca?: string;
155
+ /**
156
+ * Client certificate as PEM string or file path. If the value starts with 'file://', it will be loaded from file, otherwise treated as PEM string.
157
+ */
158
+ cert?: string;
159
+ /**
160
+ * Client private key as PEM string or file path. If the value starts with 'file://', it will be loaded from file, otherwise treated as PEM string.
161
+ */
162
+ key?: string;
163
+ /**
164
+ * Whether to reject unauthorized certificates (default: true)
165
+ */
166
+ rejectUnauthorized?: boolean;
167
+ }
150
168
  interface JobQueueConfig {
151
169
  databaseConfig: {
152
170
  connectionString?: string;
@@ -155,7 +173,7 @@ interface JobQueueConfig {
155
173
  database?: string;
156
174
  user?: string;
157
175
  password?: string;
158
- ssl?: any;
176
+ ssl?: DatabaseSSLConfig;
159
177
  };
160
178
  verbose?: boolean;
161
179
  }
@@ -190,6 +208,26 @@ interface JobQueue<PayloadMap> {
190
208
  * Get all jobs.
191
209
  */
192
210
  getAllJobs: <T extends JobType<PayloadMap>>(limit?: number, offset?: number) => Promise<JobRecord<PayloadMap, T>[]>;
211
+ /**
212
+ * Get jobs by filters.
213
+ /**
214
+ * Get jobs by filters.
215
+ */
216
+ getJobs: <T extends JobType<PayloadMap>>(filters?: {
217
+ jobType?: string;
218
+ priority?: number;
219
+ runAt?: Date | {
220
+ gt?: Date;
221
+ gte?: Date;
222
+ lt?: Date;
223
+ lte?: Date;
224
+ eq?: Date;
225
+ };
226
+ tags?: {
227
+ values: string[];
228
+ mode?: TagQueryMode;
229
+ };
230
+ }) => Promise<JobRecord<PayloadMap, T>[]>;
193
231
  /**
194
232
  * Retry a job given its ID.
195
233
  * - This will set the job status back to 'pending', clear the locked_at and locked_by, and allow it to be picked up by other workers.
@@ -218,13 +256,19 @@ interface JobQueue<PayloadMap> {
218
256
  * - The filters are:
219
257
  * - jobType: The job type to cancel.
220
258
  * - priority: The priority of the job to cancel.
221
- * - runAt: The time the job is scheduled to run at.
259
+ * - runAt: The time the job is scheduled to run at (now supports gt/gte/lt/lte/eq).
222
260
  * - tags: An object with 'values' (string[]) and 'mode' (TagQueryMode) for tag-based cancellation.
223
261
  */
224
262
  cancelAllUpcomingJobs: (filters?: {
225
263
  jobType?: string;
226
264
  priority?: number;
227
- runAt?: Date;
265
+ runAt?: Date | {
266
+ gt?: Date;
267
+ gte?: Date;
268
+ lt?: Date;
269
+ lte?: Date;
270
+ eq?: Date;
271
+ };
228
272
  tags?: {
229
273
  values: string[];
230
274
  mode?: TagQueryMode;
@@ -249,4 +293,4 @@ interface JobQueue<PayloadMap> {
249
293
  */
250
294
  declare const initJobQueue: <PayloadMap = any>(config: JobQueueConfig) => JobQueue<PayloadMap>;
251
295
 
252
- export { FailureReason, type JobEvent, JobEventType, type JobHandler, type JobHandlers, type JobOptions, type JobQueue, type JobQueueConfig, type JobRecord, type JobStatus, type JobType, type Processor, type ProcessorOptions, type TagQueryMode, initJobQueue };
296
+ export { type DatabaseSSLConfig, FailureReason, type JobEvent, JobEventType, type JobHandler, type JobHandlers, type JobOptions, type JobQueue, type JobQueueConfig, type JobRecord, type JobStatus, type JobType, type Processor, type ProcessorOptions, type TagQueryMode, initJobQueue };