@odunlamizo/node-river 1.0.8 → 1.1.1
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.
- package/README.md +91 -37
- package/dist/driver-BhanG0yg.d.cts +70 -0
- package/dist/driver-DQ6PVYVO.d.ts +70 -0
- package/dist/drivers/pg/index.cjs +74 -3
- package/dist/drivers/pg/index.cjs.map +1 -1
- package/dist/drivers/pg/index.d.cts +5 -2
- package/dist/drivers/pg/index.d.ts +5 -2
- package/dist/drivers/pg/index.js +74 -3
- package/dist/drivers/pg/index.js.map +1 -1
- package/dist/index.cjs +107 -30
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +49 -28
- package/dist/index.d.ts +49 -28
- package/dist/index.js +102 -30
- package/dist/index.js.map +1 -1
- package/dist/{insert-result-Bf0bAFvJ.d.cts → insert-result-DWZkRtk9.d.cts} +27 -26
- package/dist/{insert-result-Bf0bAFvJ.d.ts → insert-result-DWZkRtk9.d.ts} +27 -26
- package/dist/types.d.cts +42 -6
- package/dist/types.d.ts +42 -6
- package/package.json +1 -1
- package/dist/driver-okKFbSrB.d.ts +0 -54
- package/dist/driver-vSyPLsFq.d.cts +0 -54
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/utils/mappers.ts","../../../src/drivers/pg/pg-driver.ts"],"names":["query","values","result","row"],"mappings":"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","file":"index.js","sourcesContent":["import { Buffer } from 'buffer';\nimport crypto from 'crypto';\nimport { InsertOpts, JobArgs, JobState } from '../types';\n\n/**\n * Converts a bit(8) Buffer to an array of JobState values using the bit order from river_job_state_in_bitmask.\n *\n * @param bitmask - The Buffer representing the job state bitmask.\n * @returns An array of JobState values corresponding to the set bits, or null if the bitmask is null.\n */\nexport const bitmaskToJobStates = (bitmask: Buffer | null): JobState[] | null => {\n if (!bitmask || bitmask.length === 0) return null;\n // Bit order: 7=available, 6=cancelled, 5=completed, 4=discarded, 3=pending, 2=retryable, 1=running, 0=scheduled\n const allStates: JobState[] = [\n JobState.Available, // 7\n JobState.Cancelled, // 6\n JobState.Completed, // 5\n JobState.Discarded, // 4\n JobState.Pending, // 3\n JobState.Retryable, // 2\n JobState.Running, // 1\n JobState.Scheduled, // 0\n ];\n const byte = bitmask[0];\n // Map bits 7..0 to allStates\n return allStates.filter((_, i) => (byte & (1 << (7 - i))) !== 0);\n};\n\n/**\n * Maps job args and unique options to a unique key buffer.\n *\n * @param args - The job arguments to use for uniqueness computation.\n * @param opts - The insertion options, including unique options.\n * @returns A Buffer containing the unique key, or undefined if no unique options are set.\n */\nexport const mapToUniqueKey = (args: JobArgs, opts: InsertOpts): Buffer | undefined => {\n const uniqueOpts = opts.uniqueOpts;\n if (!uniqueOpts) return undefined;\n\n const keyParts: Record<string, unknown> = {};\n\n if (!uniqueOpts.excludeKind) {\n keyParts.kind = args.kind;\n }\n\n if (uniqueOpts.byArgs === true) {\n keyParts.args = args;\n } else if (Array.isArray(uniqueOpts.byArgs)) {\n keyParts.args = Object.fromEntries(uniqueOpts.byArgs.sort().map((k) => [k, args[k]]));\n }\n\n if (uniqueOpts.byQueue) {\n keyParts.queue = opts.queue;\n }\n\n if (uniqueOpts.byPeriod && opts.scheduledAt) {\n const date = new Date(opts.scheduledAt);\n const period = uniqueOpts.byPeriod;\n const timestamp = Math.floor(date.getTime() / 1000);\n const rounded = timestamp - (timestamp % period);\n keyParts.period = rounded;\n }\n\n const hash = crypto.createHash('sha256').update(JSON.stringify(keyParts)).digest();\n\n return Buffer.from(hash);\n};\n","// RiverQueue driver implementation using the 'pg' library.\nimport { Buffer } from 'buffer';\nimport { Pool, PoolClient, PoolConfig } from 'pg';\nimport { InsertOpts, InsertResult, Job, JobArgs } from '../../types';\nimport { bitmaskToJobStates, mapToUniqueKey } from '../../utils';\nimport Driver from '../driver';\nimport Options from './pg-options';\n\n// Implements the RiverQueue Driver interface using the 'pg' library.\nexport default class PgDriver implements Driver<PoolClient> {\n private readonly pool: Pool;\n\n /**\n * Creates a new PgDriver instance.\n * @param options - Options for configuring the RiverQueue pg driver connection pool. Fields include:\n * - connectionString: Database connection string\n * - connectionTimeoutMillis: Optional, connection timeout in milliseconds\n * - idleTimeoutMillis: Optional, idle timeout in milliseconds\n * - max: Optional, maximum number of clients in the pool\n */\n constructor(options: Options) {\n const config: PoolConfig = { ...options };\n this.pool = new Pool(config);\n }\n\n async verifyConnection(): Promise<void> {\n try {\n const client = await this.pool.connect();\n try {\n await client.query('SELECT 1');\n } finally {\n client.release();\n }\n } catch (error) {\n throw new Error(\n `Database connection failed: ${error instanceof Error ? error.message : String(error)}`,\n );\n }\n }\n\n async close(): Promise<void> {\n await this.pool.end();\n }\n\n async insert<T extends JobArgs>(args: T, opts: InsertOpts): Promise<InsertResult<T>> {\n const client = await this.pool.connect();\n try {\n return await this.insertTx(client, args, opts);\n } finally {\n client.release();\n }\n }\n\n async insertTx<T extends JobArgs>(\n tx: PoolClient,\n args: T,\n opts: InsertOpts,\n ): Promise<InsertResult<T>> {\n if (!opts.queue) {\n throw new Error('Queue name is required in InsertOpts');\n }\n\n if (!opts.maxAttempts) {\n throw new Error('maxAttempts is required in InsertOpts');\n }\n\n let uniqueKey: Buffer | undefined;\n if (opts.uniqueOpts) {\n uniqueKey = mapToUniqueKey(args, opts);\n }\n\n if (uniqueKey) {\n const stateList = opts.uniqueOpts?.byState || [];\n\n let query = 'SELECT * FROM river_job WHERE unique_key = $1';\n let values: (Buffer | string[])[] = [uniqueKey];\n\n if (stateList.length > 0) {\n query += ' AND state = ANY($2)';\n values.push(stateList);\n }\n\n query += ' LIMIT 1';\n\n const result = await tx.query<Omit<Job, 'uniqueStates'> & { uniqueStates: Buffer | null }>(\n query,\n values,\n );\n\n if (result.rows.length > 0) {\n const row = result.rows[0];\n\n return this.mapRowToInsertResult(row, true);\n }\n }\n\n const { kind, ...restArgs } = args;\n const columns = ['kind', 'args', 'queue', 'max_attempts'];\n const values: (string | number | Buffer)[] = [\n kind,\n JSON.stringify(restArgs),\n opts.queue,\n opts.maxAttempts,\n ];\n\n if (opts.tags) {\n columns.push('tags');\n values.push(JSON.stringify(opts.tags));\n }\n\n if (opts.priority) {\n columns.push('priority');\n values.push(opts.priority);\n }\n\n if (opts.metadata) {\n columns.push('metadata');\n values.push(JSON.stringify(opts.metadata));\n }\n\n if (opts.scheduledAt) {\n columns.push('scheduled_at');\n values.push(\n opts.scheduledAt instanceof Date ? opts.scheduledAt.toISOString() : opts.scheduledAt,\n );\n }\n\n if (uniqueKey) {\n columns.push('unique_key');\n values.push(uniqueKey);\n }\n\n const placeholders = columns.map((_, i) => `$${i + 1}`);\n const query = `INSERT INTO river_job (${columns.join(', ')}) VALUES (${placeholders.join(', ')}) RETURNING\n id,\n state,\n attempt,\n max_attempts as \"maxAttempts\",\n attempted_at as \"attemptedAt\",\n created_at as \"createdAt\",\n finalized_at as \"finalizedAt\",\n scheduled_at as \"scheduledAt\",\n priority,\n args,\n attempted_by as \"attemptedBy\",\n errors,\n kind,\n metadata,\n queue,\n tags,\n unique_key as \"uniqueKey\",\n unique_states as \"uniqueStates\"`;\n const result = await tx.query<Omit<Job, 'uniqueStates'> & { uniqueStates: Buffer | null }>(\n query,\n values,\n );\n\n const row = result.rows[0];\n if (!row) return row;\n\n return this.mapRowToInsertResult(row, false);\n }\n\n async insertMany<T extends JobArgs>(\n jobs: { args: T; opts: InsertOpts }[],\n ): Promise<InsertResult<T>[]> {\n const client = await this.pool.connect();\n try {\n await client.query('BEGIN');\n\n const results: InsertResult<T>[] = [];\n for (const job of jobs) {\n results.push(await this.insertTx(client, job.args, job.opts));\n }\n\n await client.query('COMMIT');\n\n return results;\n } catch (error) {\n await client.query('ROLLBACK');\n\n throw error;\n } finally {\n client.release();\n }\n }\n\n async getTx(): Promise<PoolClient> {\n return this.pool.connect();\n }\n\n /**\n * Helper to map a DB row to a Job<T> and InsertResult.\n */\n private mapRowToInsertResult<T extends JobArgs>(\n row: Omit<Job, 'uniqueStates'> & { uniqueStates: Buffer | null },\n skipped: boolean,\n ): InsertResult<T> {\n return {\n job: {\n ...row,\n args: { ...row.args, kind: row.kind } as T,\n uniqueStates: bitmaskToJobStates(row.uniqueStates),\n },\n skipped,\n };\n }\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../../../src/utils/mappers.ts","../../../src/drivers/pg/pg-driver.ts"],"names":["query","values","result","row"],"mappings":"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","file":"index.js","sourcesContent":["import { Buffer } from 'buffer';\nimport crypto from 'crypto';\nimport { InsertOpts, JobArgs, JobState } from '../types';\n\n/**\n * Converts a bit(8) Buffer to an array of JobState values using the bit order from river_job_state_in_bitmask.\n *\n * @param bitmask - The Buffer representing the job state bitmask.\n * @returns An array of JobState values corresponding to the set bits, or null if the bitmask is null.\n */\nexport const bitmaskToJobStates = (bitmask: Buffer | null): JobState[] | null => {\n if (!bitmask || bitmask.length === 0) return null;\n // Bit order: 7=available, 6=cancelled, 5=completed, 4=discarded, 3=pending, 2=retryable, 1=running, 0=scheduled\n const allStates: JobState[] = [\n JobState.Available, // 7\n JobState.Cancelled, // 6\n JobState.Completed, // 5\n JobState.Discarded, // 4\n JobState.Pending, // 3\n JobState.Retryable, // 2\n JobState.Running, // 1\n JobState.Scheduled, // 0\n ];\n const byte = bitmask[0];\n // Map bits 7..0 to allStates\n return allStates.filter((_, i) => (byte & (1 << (7 - i))) !== 0);\n};\n\n/**\n * Maps job args and unique options to a unique key buffer.\n *\n * @param args - The job arguments to use for uniqueness computation.\n * @param opts - The insertion options, including unique options.\n * @returns A Buffer containing the unique key, or undefined if no unique options are set.\n */\nexport const mapToUniqueKey = (args: JobArgs, opts: InsertOpts): Buffer | undefined => {\n const uniqueOpts = opts.uniqueOpts;\n if (!uniqueOpts) return undefined;\n\n const keyParts: Record<string, unknown> = {};\n\n if (!uniqueOpts.excludeKind) {\n keyParts.kind = args.kind;\n }\n\n if (uniqueOpts.byArgs === true) {\n keyParts.args = args;\n } else if (Array.isArray(uniqueOpts.byArgs)) {\n keyParts.args = Object.fromEntries(uniqueOpts.byArgs.sort().map((k) => [k, args[k]]));\n }\n\n if (uniqueOpts.byQueue) {\n keyParts.queue = opts.queue;\n }\n\n if (uniqueOpts.byPeriod && opts.scheduledAt) {\n const date = new Date(opts.scheduledAt);\n const period = uniqueOpts.byPeriod;\n const timestamp = Math.floor(date.getTime() / 1000);\n const rounded = timestamp - (timestamp % period);\n keyParts.period = rounded;\n }\n\n const hash = crypto.createHash('sha256').update(JSON.stringify(keyParts)).digest();\n\n return Buffer.from(hash);\n};\n","// RiverQueue driver implementation using the 'pg' library.\nimport { Buffer } from 'buffer';\nimport { Pool, PoolClient, PoolConfig } from 'pg';\nimport { InsertOpts, InsertResult, Job, JobArgs, JobState } from '../../types';\nimport { bitmaskToJobStates, mapToUniqueKey } from '../../utils';\nimport Driver from '../driver';\nimport Options from './pg-options';\n\n// Implements the RiverQueue Driver interface using the 'pg' library.\nexport default class PgDriver implements Driver<PoolClient> {\n private readonly pool: Pool;\n\n /**\n * Creates a new PgDriver instance.\n * @param options - Options for configuring the RiverQueue pg driver connection pool. Fields include:\n * - connectionString: Database connection string\n * - connectionTimeoutMillis: Optional, connection timeout in milliseconds\n * - idleTimeoutMillis: Optional, idle timeout in milliseconds\n * - max: Optional, maximum number of clients in the pool\n */\n constructor(options: Options) {\n const config: PoolConfig = { ...options };\n this.pool = new Pool(config);\n }\n\n async verifyConnection(): Promise<void> {\n try {\n const client = await this.pool.connect();\n try {\n await client.query('SELECT 1');\n } finally {\n client.release();\n }\n } catch (error) {\n throw new Error(\n `Database connection failed: ${error instanceof Error ? error.message : String(error)}`,\n );\n }\n }\n\n async close(): Promise<void> {\n await this.pool.end();\n }\n\n async insert<T extends JobArgs>(args: T, opts: InsertOpts): Promise<InsertResult<T>> {\n const client = await this.pool.connect();\n try {\n return await this.insertTx(client, args, opts);\n } finally {\n client.release();\n }\n }\n\n async insertTx<T extends JobArgs>(\n tx: PoolClient,\n args: T,\n opts: InsertOpts,\n ): Promise<InsertResult<T>> {\n if (!opts.maxAttempts) {\n throw new Error('maxAttempts is required in InsertOpts');\n }\n\n let uniqueKey: Buffer | undefined;\n if (opts.uniqueOpts) {\n uniqueKey = mapToUniqueKey(args, opts);\n }\n\n if (uniqueKey) {\n const stateList = opts.uniqueOpts?.byState || [];\n\n let query = 'SELECT * FROM river_job WHERE unique_key = $1';\n let values: (Buffer | string[])[] = [uniqueKey];\n\n if (stateList.length > 0) {\n query += ' AND state = ANY($2)';\n values.push(stateList);\n }\n\n query += ' LIMIT 1';\n\n const result = await tx.query<Omit<Job, 'uniqueStates'> & { uniqueStates: Buffer | null }>(\n query,\n values,\n );\n\n if (result.rows.length > 0) {\n const row = result.rows[0];\n\n return this.mapRowToInsertResult(row, true);\n }\n }\n\n const { kind, ...restArgs } = args;\n const columns = ['kind', 'args', 'queue', 'max_attempts'];\n const values: (string | number | Buffer)[] = [\n kind,\n JSON.stringify(restArgs),\n opts.queue,\n opts.maxAttempts,\n ];\n\n if (opts.tags) {\n columns.push('tags');\n values.push(JSON.stringify(opts.tags));\n }\n\n if (opts.priority) {\n columns.push('priority');\n values.push(opts.priority);\n }\n\n if (opts.metadata) {\n columns.push('metadata');\n values.push(JSON.stringify(opts.metadata));\n }\n\n if (opts.scheduledAt) {\n columns.push('scheduled_at');\n values.push(\n opts.scheduledAt instanceof Date ? opts.scheduledAt.toISOString() : opts.scheduledAt,\n );\n }\n\n if (uniqueKey) {\n columns.push('unique_key');\n values.push(uniqueKey);\n }\n\n const placeholders = columns.map((_, i) => `$${i + 1}`);\n const query = `INSERT INTO river_job (${columns.join(', ')}) VALUES (${placeholders.join(', ')}) RETURNING\n id,\n state,\n attempt,\n max_attempts as \"maxAttempts\",\n attempted_at as \"attemptedAt\",\n created_at as \"createdAt\",\n finalized_at as \"finalizedAt\",\n scheduled_at as \"scheduledAt\",\n priority,\n args,\n attempted_by as \"attemptedBy\",\n errors,\n kind,\n metadata,\n queue,\n tags,\n unique_key as \"uniqueKey\",\n unique_states as \"uniqueStates\"`;\n const result = await tx.query<Omit<Job, 'uniqueStates'> & { uniqueStates: Buffer | null }>(\n query,\n values,\n );\n\n const row = result.rows[0];\n if (!row) return row;\n\n return this.mapRowToInsertResult(row, false);\n }\n\n async insertMany<T extends JobArgs>(\n jobs: { args: T; opts: InsertOpts }[],\n ): Promise<InsertResult<T>[]> {\n const client = await this.pool.connect();\n try {\n await client.query('BEGIN');\n\n const results: InsertResult<T>[] = [];\n for (const job of jobs) {\n results.push(await this.insertTx(client, job.args, job.opts));\n }\n\n await client.query('COMMIT');\n\n return results;\n } catch (error) {\n await client.query('ROLLBACK');\n\n throw error;\n } finally {\n client.release();\n }\n }\n\n async getTx(): Promise<PoolClient> {\n return this.pool.connect();\n }\n\n async getAvailableJobs(queue: string, limit: number, clientId: string): Promise<Job[]> {\n const result = await this.pool.query<Job>(\n `\n UPDATE river_job\n SET state = 'running',\n attempt = attempt + 1,\n attempted_at = NOW(),\n attempted_by = array_append(COALESCE(attempted_by, '{}'), $1)\n WHERE id IN (\n SELECT id FROM river_job\n WHERE state = 'available'\n AND queue = $2\n AND scheduled_at <= NOW()\n ORDER BY priority, scheduled_at, id\n LIMIT $3\n FOR UPDATE SKIP LOCKED\n )\n RETURNING\n id,\n state,\n attempt,\n max_attempts as \"maxAttempts\",\n attempted_at as \"attemptedAt\",\n created_at as \"createdAt\",\n finalized_at as \"finalizedAt\",\n scheduled_at as \"scheduledAt\",\n priority,\n args,\n attempted_by as \"attemptedBy\",\n errors,\n kind,\n metadata,\n queue,\n tags,\n unique_key as \"uniqueKey\",\n unique_states as \"uniqueStates\"\n `,\n [clientId, queue, limit],\n );\n\n return result.rows;\n }\n\n async completeJob(id: number): Promise<void> {\n await this.pool.query(\n `\n UPDATE river_job\n SET state = $1,\n finalized_at = NOW()\n WHERE id = $2\n `,\n [JobState.Completed, id],\n );\n }\n\n async failJob(id: number, error: Error, attempt: number, maxAttempts: number): Promise<void> {\n const isDiscarded = attempt >= maxAttempts;\n const backoffSeconds = Math.pow(2, attempt);\n const errorEntry = JSON.stringify({ error: error.message, attempt });\n\n await this.pool.query(\n `\n UPDATE river_job\n SET state = $1,\n finalized_at = CASE WHEN $2 THEN NOW() ELSE NULL END,\n scheduled_at = CASE WHEN $2 THEN scheduled_at ELSE NOW() + ($3 || ' seconds')::interval END,\n errors = array_append(COALESCE(errors, '{}'), $4::jsonb)\n WHERE id = $5\n `,\n [\n isDiscarded ? JobState.Discarded : JobState.Retryable,\n isDiscarded,\n backoffSeconds,\n errorEntry,\n id,\n ],\n );\n }\n\n /**\n * Helper to map a DB row to a Job<T> and InsertResult.\n */\n private mapRowToInsertResult<T extends JobArgs>(\n row: Omit<Job, 'uniqueStates'> & { uniqueStates: Buffer | null },\n skipped: boolean,\n ): InsertResult<T> {\n return {\n job: {\n ...row,\n args: { ...row.args, kind: row.kind } as T,\n uniqueStates: bitmaskToJobStates(row.uniqueStates),\n },\n skipped,\n };\n }\n}\n"]}
|
package/dist/index.cjs
CHANGED
|
@@ -1,79 +1,156 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
+
var os = require('os');
|
|
4
|
+
var process = require('process');
|
|
5
|
+
var timers = require('timers');
|
|
6
|
+
|
|
7
|
+
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
8
|
+
|
|
9
|
+
var os__default = /*#__PURE__*/_interopDefault(os);
|
|
10
|
+
var process__default = /*#__PURE__*/_interopDefault(process);
|
|
11
|
+
|
|
12
|
+
// src/client.ts
|
|
13
|
+
|
|
14
|
+
// src/utils/constants.ts
|
|
15
|
+
var CLIENT_CONFIGURATION_DEFAULTS = {
|
|
16
|
+
pollInterval: 1e3
|
|
17
|
+
};
|
|
18
|
+
|
|
3
19
|
// src/client.ts
|
|
4
20
|
var RiverClient = class {
|
|
5
21
|
/**
|
|
6
22
|
* Creates a new RiverClient instance.
|
|
7
|
-
* @param driver - The
|
|
8
|
-
* @param configuration - Client
|
|
23
|
+
* @param driver - The driver implementation (e.g. PgDriver).
|
|
24
|
+
* @param configuration - Client options: queues, max attempts, poll interval, and client ID.
|
|
9
25
|
*/
|
|
10
26
|
constructor(driver, configuration) {
|
|
27
|
+
this.running = /* @__PURE__ */ new Map();
|
|
28
|
+
this.stopped = false;
|
|
29
|
+
this.pollTimer = null;
|
|
30
|
+
this.workers = /* @__PURE__ */ new Map();
|
|
11
31
|
this.driver = driver;
|
|
12
32
|
this.configuration = configuration;
|
|
33
|
+
this.clientId = configuration.clientId ?? `${os__default.default.hostname()}-${process__default.default.pid}`;
|
|
13
34
|
}
|
|
14
35
|
/**
|
|
15
|
-
*
|
|
36
|
+
* Verifies the driver can reach the database. Throws if the connection fails.
|
|
16
37
|
*/
|
|
17
|
-
verifyConnection() {
|
|
38
|
+
async verifyConnection() {
|
|
18
39
|
return this.driver.verifyConnection();
|
|
19
40
|
}
|
|
20
41
|
/**
|
|
21
|
-
*
|
|
42
|
+
* Stops the polling loop (if running) and closes all database connections.
|
|
43
|
+
* Always call this on shutdown to avoid resource leaks.
|
|
22
44
|
*/
|
|
23
|
-
close() {
|
|
24
|
-
|
|
45
|
+
async close() {
|
|
46
|
+
this.stopped = true;
|
|
47
|
+
if (this.pollTimer) timers.clearTimeout(this.pollTimer);
|
|
48
|
+
await this.driver.close();
|
|
25
49
|
}
|
|
26
50
|
/**
|
|
27
|
-
* Inserts a job into the
|
|
28
|
-
* @param args -
|
|
29
|
-
* @param opts -
|
|
30
|
-
* @returns
|
|
31
|
-
* including the job and whether the insert was skipped due to uniqueness.
|
|
51
|
+
* Inserts a single job into the specified queue.
|
|
52
|
+
* @param args - Job arguments including `kind` and any job-specific fields.
|
|
53
|
+
* @param opts - Insertion options. `queue` is required; `maxAttempts` defaults to the client configuration value.
|
|
54
|
+
* @returns The inserted job and a `skipped` flag indicating if it was deduplicated.
|
|
32
55
|
*/
|
|
33
|
-
insert(args, opts
|
|
56
|
+
async insert(args, opts) {
|
|
34
57
|
const defaultOpts = {
|
|
35
|
-
queue: this.configuration.defaultQueue,
|
|
36
58
|
maxAttempts: this.configuration.maxAttempts,
|
|
37
59
|
...opts
|
|
38
60
|
};
|
|
39
61
|
return this.driver.insert(args, defaultOpts);
|
|
40
62
|
}
|
|
41
63
|
/**
|
|
42
|
-
* Inserts a job
|
|
43
|
-
*
|
|
44
|
-
*
|
|
45
|
-
* @param
|
|
46
|
-
* @param
|
|
47
|
-
* @
|
|
48
|
-
* @returns A promise that resolves to the result of the insertion operation,
|
|
49
|
-
* including the job and whether the insert was skipped due to uniqueness.
|
|
64
|
+
* Inserts a single job within an existing transaction. Use this when the job
|
|
65
|
+
* should only be enqueued if the surrounding transaction commits.
|
|
66
|
+
* @param tx - The active transaction object (type is driver-specific).
|
|
67
|
+
* @param args - Job arguments including `kind` and any job-specific fields.
|
|
68
|
+
* @param opts - Insertion options. `queue` is required; `maxAttempts` defaults to the client configuration value.
|
|
69
|
+
* @returns The inserted job and a `skipped` flag indicating if it was deduplicated.
|
|
50
70
|
*/
|
|
51
|
-
insertTx(tx, args, opts
|
|
71
|
+
async insertTx(tx, args, opts) {
|
|
52
72
|
const defaultOpts = {
|
|
53
|
-
queue: this.configuration.defaultQueue,
|
|
54
73
|
maxAttempts: this.configuration.maxAttempts,
|
|
55
74
|
...opts
|
|
56
75
|
};
|
|
57
76
|
return this.driver.insertTx(tx, args, defaultOpts);
|
|
58
77
|
}
|
|
59
78
|
/**
|
|
60
|
-
* Inserts multiple jobs in
|
|
61
|
-
*
|
|
62
|
-
*
|
|
63
|
-
* @param jobs - Array of job argument and option pairs to insert.
|
|
64
|
-
* @returns A promise that resolves to an array of InsertResult objects for each job.
|
|
79
|
+
* Inserts multiple jobs in a single transaction. If any insert fails, all are rolled back.
|
|
80
|
+
* @param jobs - Array of `{ args, opts }` pairs. Each `opts` must include a `queue`.
|
|
81
|
+
* @returns An array of InsertResult objects in the same order as the input.
|
|
65
82
|
*/
|
|
66
83
|
async insertMany(jobs) {
|
|
67
84
|
const jobsWithDefaults = jobs.map((job) => ({
|
|
68
85
|
args: job.args,
|
|
69
86
|
opts: {
|
|
70
|
-
queue: this.configuration.defaultQueue,
|
|
71
87
|
maxAttempts: this.configuration.maxAttempts,
|
|
72
88
|
...job.opts
|
|
73
89
|
}
|
|
74
90
|
}));
|
|
75
91
|
return this.driver.insertMany(jobsWithDefaults);
|
|
76
92
|
}
|
|
93
|
+
/**
|
|
94
|
+
* Registers a worker for a specific job kind. When a job of this kind is claimed
|
|
95
|
+
* from the queue, the worker's `work()` method will be called with the job.
|
|
96
|
+
* Must be called before `work()` for the worker to receive jobs.
|
|
97
|
+
* @param kind - The job kind string that this worker handles (e.g. `"send_email"`).
|
|
98
|
+
* @param worker - The worker instance that implements the `Worker<T>` interface.
|
|
99
|
+
*/
|
|
100
|
+
addWorker(kind, worker) {
|
|
101
|
+
this.workers.set(kind, worker);
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Begins polling all configured queues and dispatching jobs to registered workers.
|
|
105
|
+
* Each queue is polled independently with its own concurrency limit.
|
|
106
|
+
* No-op if `queues` is not configured.
|
|
107
|
+
*/
|
|
108
|
+
work() {
|
|
109
|
+
this.stopped = false;
|
|
110
|
+
this.poll();
|
|
111
|
+
}
|
|
112
|
+
poll() {
|
|
113
|
+
if (this.stopped) return;
|
|
114
|
+
this.fetchAndWork().finally(() => {
|
|
115
|
+
this.pollTimer = timers.setTimeout(
|
|
116
|
+
() => this.poll(),
|
|
117
|
+
this.configuration.pollInterval ?? CLIENT_CONFIGURATION_DEFAULTS.pollInterval
|
|
118
|
+
);
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
async fetchAndWork() {
|
|
122
|
+
const queues = Object.entries(this.configuration.queues ?? {});
|
|
123
|
+
for (const [queue, queueConfig] of queues) {
|
|
124
|
+
const running = this.running.get(queue) ?? 0;
|
|
125
|
+
const slots = queueConfig.concurrency - running;
|
|
126
|
+
if (slots <= 0) continue;
|
|
127
|
+
const jobs = await this.driver.getAvailableJobs(queue, slots, this.clientId);
|
|
128
|
+
for (const job of jobs) {
|
|
129
|
+
this.running.set(job.queue, (this.running.get(job.queue) ?? 0) + 1);
|
|
130
|
+
this.processJob(job).finally(() => {
|
|
131
|
+
this.running.set(job.queue, Math.max(0, (this.running.get(job.queue) ?? 0) - 1));
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
async processJob(job) {
|
|
137
|
+
const worker = this.workers.get(job.kind);
|
|
138
|
+
if (!worker) {
|
|
139
|
+
await this.driver.failJob(
|
|
140
|
+
job.id,
|
|
141
|
+
new Error(`No worker registered for kind: ${job.kind}`),
|
|
142
|
+
job.attempt,
|
|
143
|
+
job.maxAttempts
|
|
144
|
+
);
|
|
145
|
+
return;
|
|
146
|
+
}
|
|
147
|
+
try {
|
|
148
|
+
await worker.work(job);
|
|
149
|
+
await this.driver.completeJob(job.id);
|
|
150
|
+
} catch (error) {
|
|
151
|
+
await this.driver.failJob(job.id, error, job.attempt, job.maxAttempts);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
77
154
|
};
|
|
78
155
|
|
|
79
156
|
exports.RiverClient = RiverClient;
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/client.ts"],"names":[],"mappings":";;;AAMA,IAAqB,cAArB,MAA2D;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASzD,WAAA,CAAY,QAAW,aAAA,EAAoC;AACzD,IAAA,IAAA,CAAK,MAAA,GAAS,MAAA;AACd,IAAA,IAAA,CAAK,aAAA,GAAgB,aAAA;AAAA,EACvB;AAAA;AAAA;AAAA;AAAA,EAKA,gBAAA,GAAkC;AAChC,IAAA,OAAO,IAAA,CAAK,OAAO,gBAAA,EAAiB;AAAA,EACtC;AAAA;AAAA;AAAA;AAAA,EAKA,KAAA,GAAuB;AACrB,IAAA,OAAO,IAAA,CAAK,OAAO,KAAA,EAAM;AAAA,EAC3B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,MAAA,CAA0B,IAAA,EAAS,IAAA,GAAmB,EAAC,EAA6B;AAClF,IAAA,MAAM,WAAA,GAA0B;AAAA,MAC9B,KAAA,EAAO,KAAK,aAAA,CAAc,YAAA;AAAA,MAC1B,WAAA,EAAa,KAAK,aAAA,CAAc,WAAA;AAAA,MAChC,GAAG;AAAA,KACL;AAEA,IAAA,OAAO,IAAA,CAAK,MAAA,CAAO,MAAA,CAAO,IAAA,EAAM,WAAW,CAAA;AAAA,EAC7C;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYA,QAAA,CAA4B,EAAA,EAAQ,IAAA,EAAS,IAAA,GAAmB,EAAC,EAA6B;AAC5F,IAAA,MAAM,WAAA,GAA0B;AAAA,MAC9B,KAAA,EAAO,KAAK,aAAA,CAAc,YAAA;AAAA,MAC1B,WAAA,EAAa,KAAK,aAAA,CAAc,WAAA;AAAA,MAChC,GAAG;AAAA,KACL;AAEA,IAAA,OAAO,IAAA,CAAK,MAAA,CAAO,QAAA,CAAS,EAAA,EAAI,MAAM,WAAW,CAAA;AAAA,EACnD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,MAAM,WACJ,IAAA,EAC4B;AAC5B,IAAA,MAAM,gBAAA,GAAmB,IAAA,CAAK,GAAA,CAAI,CAAC,GAAA,MAAS;AAAA,MAC1C,MAAM,GAAA,CAAI,IAAA;AAAA,MACV,IAAA,EAAM;AAAA,QACJ,KAAA,EAAO,KAAK,aAAA,CAAc,YAAA;AAAA,QAC1B,WAAA,EAAa,KAAK,aAAA,CAAc,WAAA;AAAA,QAChC,GAAG,GAAA,CAAI;AAAA;AACT,KACF,CAAE,CAAA;AAEF,IAAA,OAAO,IAAA,CAAK,MAAA,CAAO,UAAA,CAAW,gBAAgB,CAAA;AAAA,EAChD;AACF","file":"index.cjs","sourcesContent":["import { Driver } from './drivers';\nimport { ClientConfiguration, InsertOpts, InsertResult, JobArgs } from './types';\n\n/**\n * Provides methods to enqueue jobs and manage queue operations.\n */\nexport default class RiverClient<D extends Driver<Tx>, Tx> {\n private readonly driver: D;\n private readonly configuration: ClientConfiguration;\n\n /**\n * Creates a new RiverClient instance.\n * @param driver - The queue driver implementation.\n * @param configuration - Client configuration options.\n */\n constructor(driver: D, configuration: ClientConfiguration) {\n this.driver = driver;\n this.configuration = configuration;\n }\n\n /**\n * Checks if the driver can connect to the database. Throws on failure.\n */\n verifyConnection(): Promise<void> {\n return this.driver.verifyConnection();\n }\n\n /**\n * Closes all database connections and cleans up resources.\n */\n close(): Promise<void> {\n return this.driver.close();\n }\n\n /**\n * Inserts a job into the queue with the specified arguments and options.\n * @param args - The job arguments to insert.\n * @param opts - Optional insertion options.\n * @returns A promise that resolves to the result of the insertion operation,\n * including the job and whether the insert was skipped due to uniqueness.\n */\n insert<T extends JobArgs>(args: T, opts: InsertOpts = {}): Promise<InsertResult<T>> {\n const defaultOpts: InsertOpts = {\n queue: this.configuration.defaultQueue,\n maxAttempts: this.configuration.maxAttempts,\n ...opts,\n };\n\n return this.driver.insert(args, defaultOpts);\n }\n\n /**\n * Inserts a job into the queue within an existing transaction or session.\n * The transaction type (Tx) is determined by the driver implementation.\n *\n * @param tx - The transaction or session object to use for the insert.\n * @param args - The job arguments to insert.\n * @param opts - Optional insertion options.\n * @returns A promise that resolves to the result of the insertion operation,\n * including the job and whether the insert was skipped due to uniqueness.\n */\n insertTx<T extends JobArgs>(tx: Tx, args: T, opts: InsertOpts = {}): Promise<InsertResult<T>> {\n const defaultOpts: InsertOpts = {\n queue: this.configuration.defaultQueue,\n maxAttempts: this.configuration.maxAttempts,\n ...opts,\n };\n\n return this.driver.insertTx(tx, args, defaultOpts);\n }\n\n /**\n * Inserts multiple jobs in sequence within a single transaction.\n * If any insert fails, all previous inserts in the batch are rolled back.\n *\n * @param jobs - Array of job argument and option pairs to insert.\n * @returns A promise that resolves to an array of InsertResult objects for each job.\n */\n async insertMany<T extends JobArgs>(\n jobs: { args: T; opts: InsertOpts }[],\n ): Promise<InsertResult<T>[]> {\n const jobsWithDefaults = jobs.map((job) => ({\n args: job.args,\n opts: {\n queue: this.configuration.defaultQueue,\n maxAttempts: this.configuration.maxAttempts,\n ...job.opts,\n },\n }));\n\n return this.driver.insertMany(jobsWithDefaults);\n }\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/utils/constants.ts","../src/client.ts"],"names":["os","process","clearTimeout","setTimeout"],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * Default values applied when optional fields are not provided in ClientConfiguration.\n */\nexport const CLIENT_CONFIGURATION_DEFAULTS = {\n pollInterval: 1000,\n};\n","import os from 'os';\nimport process from 'process';\nimport { clearTimeout, setTimeout } from 'timers';\nimport { Driver } from './drivers';\nimport { ClientConfiguration, InsertOpts, InsertResult, Job, JobArgs, Worker } from './types';\nimport { CLIENT_CONFIGURATION_DEFAULTS } from './utils';\n\n/**\n * RiverClient is the main entry point for interacting with the River job queue.\n * It supports two usage modes:\n * - Insertion only: enqueue jobs without processing them.\n * - Worker mode: register workers and call `work()` to start polling and processing jobs.\n */\nexport default class RiverClient<D extends Driver<Tx>, Tx> {\n private readonly running: Map<string, number> = new Map();\n private stopped = false;\n private pollTimer: ReturnType<typeof setTimeout> | null = null;\n private readonly driver: D;\n private readonly configuration: ClientConfiguration;\n private readonly workers: Map<string, Worker> = new Map();\n private readonly clientId: string;\n\n /**\n * Creates a new RiverClient instance.\n * @param driver - The driver implementation (e.g. PgDriver).\n * @param configuration - Client options: queues, max attempts, poll interval, and client ID.\n */\n constructor(driver: D, configuration: ClientConfiguration) {\n this.driver = driver;\n this.configuration = configuration;\n this.clientId = configuration.clientId ?? `${os.hostname()}-${process.pid}`;\n }\n\n /**\n * Verifies the driver can reach the database. Throws if the connection fails.\n */\n async verifyConnection(): Promise<void> {\n return this.driver.verifyConnection();\n }\n\n /**\n * Stops the polling loop (if running) and closes all database connections.\n * Always call this on shutdown to avoid resource leaks.\n */\n async close(): Promise<void> {\n this.stopped = true;\n if (this.pollTimer) clearTimeout(this.pollTimer);\n await this.driver.close();\n }\n\n /**\n * Inserts a single job into the specified queue.\n * @param args - Job arguments including `kind` and any job-specific fields.\n * @param opts - Insertion options. `queue` is required; `maxAttempts` defaults to the client configuration value.\n * @returns The inserted job and a `skipped` flag indicating if it was deduplicated.\n */\n async insert<T extends JobArgs>(args: T, opts: InsertOpts): Promise<InsertResult<T>> {\n const defaultOpts: InsertOpts = {\n maxAttempts: this.configuration.maxAttempts,\n ...opts,\n };\n\n return this.driver.insert(args, defaultOpts);\n }\n\n /**\n * Inserts a single job within an existing transaction. Use this when the job\n * should only be enqueued if the surrounding transaction commits.\n * @param tx - The active transaction object (type is driver-specific).\n * @param args - Job arguments including `kind` and any job-specific fields.\n * @param opts - Insertion options. `queue` is required; `maxAttempts` defaults to the client configuration value.\n * @returns The inserted job and a `skipped` flag indicating if it was deduplicated.\n */\n async insertTx<T extends JobArgs>(tx: Tx, args: T, opts: InsertOpts): Promise<InsertResult<T>> {\n const defaultOpts: InsertOpts = {\n maxAttempts: this.configuration.maxAttempts,\n ...opts,\n };\n\n return this.driver.insertTx(tx, args, defaultOpts);\n }\n\n /**\n * Inserts multiple jobs in a single transaction. If any insert fails, all are rolled back.\n * @param jobs - Array of `{ args, opts }` pairs. Each `opts` must include a `queue`.\n * @returns An array of InsertResult objects in the same order as the input.\n */\n async insertMany<T extends JobArgs>(\n jobs: { args: T; opts: InsertOpts }[],\n ): Promise<InsertResult<T>[]> {\n const jobsWithDefaults = jobs.map((job) => ({\n args: job.args,\n opts: {\n maxAttempts: this.configuration.maxAttempts,\n ...job.opts,\n },\n }));\n\n return this.driver.insertMany(jobsWithDefaults);\n }\n\n /**\n * Registers a worker for a specific job kind. When a job of this kind is claimed\n * from the queue, the worker's `work()` method will be called with the job.\n * Must be called before `work()` for the worker to receive jobs.\n * @param kind - The job kind string that this worker handles (e.g. `\"send_email\"`).\n * @param worker - The worker instance that implements the `Worker<T>` interface.\n */\n addWorker<T extends JobArgs>(kind: string, worker: Worker<T>): void {\n this.workers.set(kind, worker);\n }\n\n /**\n * Begins polling all configured queues and dispatching jobs to registered workers.\n * Each queue is polled independently with its own concurrency limit.\n * No-op if `queues` is not configured.\n */\n work(): void {\n this.stopped = false;\n this.poll();\n }\n\n private poll(): void {\n if (this.stopped) return;\n\n this.fetchAndWork().finally(() => {\n this.pollTimer = setTimeout(\n () => this.poll(),\n this.configuration.pollInterval ?? CLIENT_CONFIGURATION_DEFAULTS.pollInterval,\n );\n });\n }\n\n private async fetchAndWork(): Promise<void> {\n const queues = Object.entries(this.configuration.queues ?? {});\n\n for (const [queue, queueConfig] of queues) {\n const running = this.running.get(queue) ?? 0;\n const slots = queueConfig.concurrency - running;\n if (slots <= 0) continue;\n\n const jobs = await this.driver.getAvailableJobs(queue, slots, this.clientId);\n\n for (const job of jobs) {\n this.running.set(job.queue, (this.running.get(job.queue) ?? 0) + 1);\n this.processJob(job).finally(() => {\n this.running.set(job.queue, Math.max(0, (this.running.get(job.queue) ?? 0) - 1));\n });\n }\n }\n }\n\n private async processJob(job: Job): Promise<void> {\n const worker = this.workers.get(job.kind);\n\n if (!worker) {\n await this.driver.failJob(\n job.id,\n new Error(`No worker registered for kind: ${job.kind}`),\n job.attempt,\n job.maxAttempts,\n );\n return;\n }\n\n try {\n await worker.work(job);\n await this.driver.completeJob(job.id);\n } catch (error) {\n await this.driver.failJob(job.id, error as Error, job.attempt, job.maxAttempts);\n }\n }\n}\n"]}
|
package/dist/index.d.cts
CHANGED
|
@@ -1,58 +1,79 @@
|
|
|
1
|
-
import { D as Driver } from './driver-
|
|
2
|
-
import { ClientConfiguration } from './types.cjs';
|
|
3
|
-
import { J as JobArgs, I as InsertOpts, a as InsertResult } from './insert-result-
|
|
1
|
+
import { D as Driver } from './driver-BhanG0yg.cjs';
|
|
2
|
+
import { ClientConfiguration, Worker } from './types.cjs';
|
|
3
|
+
import { J as JobArgs, I as InsertOpts, a as InsertResult } from './insert-result-DWZkRtk9.cjs';
|
|
4
4
|
import 'buffer';
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
|
-
*
|
|
7
|
+
* RiverClient is the main entry point for interacting with the River job queue.
|
|
8
|
+
* It supports two usage modes:
|
|
9
|
+
* - Insertion only: enqueue jobs without processing them.
|
|
10
|
+
* - Worker mode: register workers and call `work()` to start polling and processing jobs.
|
|
8
11
|
*/
|
|
9
12
|
declare class RiverClient<D extends Driver<Tx>, Tx> {
|
|
13
|
+
private readonly running;
|
|
14
|
+
private stopped;
|
|
15
|
+
private pollTimer;
|
|
10
16
|
private readonly driver;
|
|
11
17
|
private readonly configuration;
|
|
18
|
+
private readonly workers;
|
|
19
|
+
private readonly clientId;
|
|
12
20
|
/**
|
|
13
21
|
* Creates a new RiverClient instance.
|
|
14
|
-
* @param driver - The
|
|
15
|
-
* @param configuration - Client
|
|
22
|
+
* @param driver - The driver implementation (e.g. PgDriver).
|
|
23
|
+
* @param configuration - Client options: queues, max attempts, poll interval, and client ID.
|
|
16
24
|
*/
|
|
17
25
|
constructor(driver: D, configuration: ClientConfiguration);
|
|
18
26
|
/**
|
|
19
|
-
*
|
|
27
|
+
* Verifies the driver can reach the database. Throws if the connection fails.
|
|
20
28
|
*/
|
|
21
29
|
verifyConnection(): Promise<void>;
|
|
22
30
|
/**
|
|
23
|
-
*
|
|
31
|
+
* Stops the polling loop (if running) and closes all database connections.
|
|
32
|
+
* Always call this on shutdown to avoid resource leaks.
|
|
24
33
|
*/
|
|
25
34
|
close(): Promise<void>;
|
|
26
35
|
/**
|
|
27
|
-
* Inserts a job into the
|
|
28
|
-
* @param args -
|
|
29
|
-
* @param opts -
|
|
30
|
-
* @returns
|
|
31
|
-
* including the job and whether the insert was skipped due to uniqueness.
|
|
36
|
+
* Inserts a single job into the specified queue.
|
|
37
|
+
* @param args - Job arguments including `kind` and any job-specific fields.
|
|
38
|
+
* @param opts - Insertion options. `queue` is required; `maxAttempts` defaults to the client configuration value.
|
|
39
|
+
* @returns The inserted job and a `skipped` flag indicating if it was deduplicated.
|
|
32
40
|
*/
|
|
33
|
-
insert<T extends JobArgs>(args: T, opts
|
|
41
|
+
insert<T extends JobArgs>(args: T, opts: InsertOpts): Promise<InsertResult<T>>;
|
|
34
42
|
/**
|
|
35
|
-
* Inserts a job
|
|
36
|
-
*
|
|
37
|
-
*
|
|
38
|
-
* @param
|
|
39
|
-
* @param
|
|
40
|
-
* @
|
|
41
|
-
* @returns A promise that resolves to the result of the insertion operation,
|
|
42
|
-
* including the job and whether the insert was skipped due to uniqueness.
|
|
43
|
+
* Inserts a single job within an existing transaction. Use this when the job
|
|
44
|
+
* should only be enqueued if the surrounding transaction commits.
|
|
45
|
+
* @param tx - The active transaction object (type is driver-specific).
|
|
46
|
+
* @param args - Job arguments including `kind` and any job-specific fields.
|
|
47
|
+
* @param opts - Insertion options. `queue` is required; `maxAttempts` defaults to the client configuration value.
|
|
48
|
+
* @returns The inserted job and a `skipped` flag indicating if it was deduplicated.
|
|
43
49
|
*/
|
|
44
|
-
insertTx<T extends JobArgs>(tx: Tx, args: T, opts
|
|
50
|
+
insertTx<T extends JobArgs>(tx: Tx, args: T, opts: InsertOpts): Promise<InsertResult<T>>;
|
|
45
51
|
/**
|
|
46
|
-
* Inserts multiple jobs in
|
|
47
|
-
*
|
|
48
|
-
*
|
|
49
|
-
* @param jobs - Array of job argument and option pairs to insert.
|
|
50
|
-
* @returns A promise that resolves to an array of InsertResult objects for each job.
|
|
52
|
+
* Inserts multiple jobs in a single transaction. If any insert fails, all are rolled back.
|
|
53
|
+
* @param jobs - Array of `{ args, opts }` pairs. Each `opts` must include a `queue`.
|
|
54
|
+
* @returns An array of InsertResult objects in the same order as the input.
|
|
51
55
|
*/
|
|
52
56
|
insertMany<T extends JobArgs>(jobs: {
|
|
53
57
|
args: T;
|
|
54
58
|
opts: InsertOpts;
|
|
55
59
|
}[]): Promise<InsertResult<T>[]>;
|
|
60
|
+
/**
|
|
61
|
+
* Registers a worker for a specific job kind. When a job of this kind is claimed
|
|
62
|
+
* from the queue, the worker's `work()` method will be called with the job.
|
|
63
|
+
* Must be called before `work()` for the worker to receive jobs.
|
|
64
|
+
* @param kind - The job kind string that this worker handles (e.g. `"send_email"`).
|
|
65
|
+
* @param worker - The worker instance that implements the `Worker<T>` interface.
|
|
66
|
+
*/
|
|
67
|
+
addWorker<T extends JobArgs>(kind: string, worker: Worker<T>): void;
|
|
68
|
+
/**
|
|
69
|
+
* Begins polling all configured queues and dispatching jobs to registered workers.
|
|
70
|
+
* Each queue is polled independently with its own concurrency limit.
|
|
71
|
+
* No-op if `queues` is not configured.
|
|
72
|
+
*/
|
|
73
|
+
work(): void;
|
|
74
|
+
private poll;
|
|
75
|
+
private fetchAndWork;
|
|
76
|
+
private processJob;
|
|
56
77
|
}
|
|
57
78
|
|
|
58
79
|
export { RiverClient };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,58 +1,79 @@
|
|
|
1
|
-
import { D as Driver } from './driver-
|
|
2
|
-
import { ClientConfiguration } from './types.js';
|
|
3
|
-
import { J as JobArgs, I as InsertOpts, a as InsertResult } from './insert-result-
|
|
1
|
+
import { D as Driver } from './driver-DQ6PVYVO.js';
|
|
2
|
+
import { ClientConfiguration, Worker } from './types.js';
|
|
3
|
+
import { J as JobArgs, I as InsertOpts, a as InsertResult } from './insert-result-DWZkRtk9.js';
|
|
4
4
|
import 'buffer';
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
|
-
*
|
|
7
|
+
* RiverClient is the main entry point for interacting with the River job queue.
|
|
8
|
+
* It supports two usage modes:
|
|
9
|
+
* - Insertion only: enqueue jobs without processing them.
|
|
10
|
+
* - Worker mode: register workers and call `work()` to start polling and processing jobs.
|
|
8
11
|
*/
|
|
9
12
|
declare class RiverClient<D extends Driver<Tx>, Tx> {
|
|
13
|
+
private readonly running;
|
|
14
|
+
private stopped;
|
|
15
|
+
private pollTimer;
|
|
10
16
|
private readonly driver;
|
|
11
17
|
private readonly configuration;
|
|
18
|
+
private readonly workers;
|
|
19
|
+
private readonly clientId;
|
|
12
20
|
/**
|
|
13
21
|
* Creates a new RiverClient instance.
|
|
14
|
-
* @param driver - The
|
|
15
|
-
* @param configuration - Client
|
|
22
|
+
* @param driver - The driver implementation (e.g. PgDriver).
|
|
23
|
+
* @param configuration - Client options: queues, max attempts, poll interval, and client ID.
|
|
16
24
|
*/
|
|
17
25
|
constructor(driver: D, configuration: ClientConfiguration);
|
|
18
26
|
/**
|
|
19
|
-
*
|
|
27
|
+
* Verifies the driver can reach the database. Throws if the connection fails.
|
|
20
28
|
*/
|
|
21
29
|
verifyConnection(): Promise<void>;
|
|
22
30
|
/**
|
|
23
|
-
*
|
|
31
|
+
* Stops the polling loop (if running) and closes all database connections.
|
|
32
|
+
* Always call this on shutdown to avoid resource leaks.
|
|
24
33
|
*/
|
|
25
34
|
close(): Promise<void>;
|
|
26
35
|
/**
|
|
27
|
-
* Inserts a job into the
|
|
28
|
-
* @param args -
|
|
29
|
-
* @param opts -
|
|
30
|
-
* @returns
|
|
31
|
-
* including the job and whether the insert was skipped due to uniqueness.
|
|
36
|
+
* Inserts a single job into the specified queue.
|
|
37
|
+
* @param args - Job arguments including `kind` and any job-specific fields.
|
|
38
|
+
* @param opts - Insertion options. `queue` is required; `maxAttempts` defaults to the client configuration value.
|
|
39
|
+
* @returns The inserted job and a `skipped` flag indicating if it was deduplicated.
|
|
32
40
|
*/
|
|
33
|
-
insert<T extends JobArgs>(args: T, opts
|
|
41
|
+
insert<T extends JobArgs>(args: T, opts: InsertOpts): Promise<InsertResult<T>>;
|
|
34
42
|
/**
|
|
35
|
-
* Inserts a job
|
|
36
|
-
*
|
|
37
|
-
*
|
|
38
|
-
* @param
|
|
39
|
-
* @param
|
|
40
|
-
* @
|
|
41
|
-
* @returns A promise that resolves to the result of the insertion operation,
|
|
42
|
-
* including the job and whether the insert was skipped due to uniqueness.
|
|
43
|
+
* Inserts a single job within an existing transaction. Use this when the job
|
|
44
|
+
* should only be enqueued if the surrounding transaction commits.
|
|
45
|
+
* @param tx - The active transaction object (type is driver-specific).
|
|
46
|
+
* @param args - Job arguments including `kind` and any job-specific fields.
|
|
47
|
+
* @param opts - Insertion options. `queue` is required; `maxAttempts` defaults to the client configuration value.
|
|
48
|
+
* @returns The inserted job and a `skipped` flag indicating if it was deduplicated.
|
|
43
49
|
*/
|
|
44
|
-
insertTx<T extends JobArgs>(tx: Tx, args: T, opts
|
|
50
|
+
insertTx<T extends JobArgs>(tx: Tx, args: T, opts: InsertOpts): Promise<InsertResult<T>>;
|
|
45
51
|
/**
|
|
46
|
-
* Inserts multiple jobs in
|
|
47
|
-
*
|
|
48
|
-
*
|
|
49
|
-
* @param jobs - Array of job argument and option pairs to insert.
|
|
50
|
-
* @returns A promise that resolves to an array of InsertResult objects for each job.
|
|
52
|
+
* Inserts multiple jobs in a single transaction. If any insert fails, all are rolled back.
|
|
53
|
+
* @param jobs - Array of `{ args, opts }` pairs. Each `opts` must include a `queue`.
|
|
54
|
+
* @returns An array of InsertResult objects in the same order as the input.
|
|
51
55
|
*/
|
|
52
56
|
insertMany<T extends JobArgs>(jobs: {
|
|
53
57
|
args: T;
|
|
54
58
|
opts: InsertOpts;
|
|
55
59
|
}[]): Promise<InsertResult<T>[]>;
|
|
60
|
+
/**
|
|
61
|
+
* Registers a worker for a specific job kind. When a job of this kind is claimed
|
|
62
|
+
* from the queue, the worker's `work()` method will be called with the job.
|
|
63
|
+
* Must be called before `work()` for the worker to receive jobs.
|
|
64
|
+
* @param kind - The job kind string that this worker handles (e.g. `"send_email"`).
|
|
65
|
+
* @param worker - The worker instance that implements the `Worker<T>` interface.
|
|
66
|
+
*/
|
|
67
|
+
addWorker<T extends JobArgs>(kind: string, worker: Worker<T>): void;
|
|
68
|
+
/**
|
|
69
|
+
* Begins polling all configured queues and dispatching jobs to registered workers.
|
|
70
|
+
* Each queue is polled independently with its own concurrency limit.
|
|
71
|
+
* No-op if `queues` is not configured.
|
|
72
|
+
*/
|
|
73
|
+
work(): void;
|
|
74
|
+
private poll;
|
|
75
|
+
private fetchAndWork;
|
|
76
|
+
private processJob;
|
|
56
77
|
}
|
|
57
78
|
|
|
58
79
|
export { RiverClient };
|