pg-boss 12.3.1 → 12.4.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.
package/dist/index.d.mts CHANGED
@@ -108,11 +108,11 @@ interface JobFetchOptions {
108
108
  }
109
109
  type WorkOptions = JobFetchOptions & JobPollingOptions;
110
110
  type FetchOptions = JobFetchOptions & ConnectionOptions;
111
- interface WorkHandler<ReqData> {
112
- (job: Job<ReqData>[]): Promise<any>;
111
+ interface WorkHandler<ReqData, ResData = any> {
112
+ (job: Job<ReqData>[]): Promise<ResData>;
113
113
  }
114
- interface WorkWithMetadataHandler<ReqData> {
115
- (job: JobWithMetadata<ReqData>[]): Promise<any>;
114
+ interface WorkWithMetadataHandler<ReqData, ResData = any> {
115
+ (job: JobWithMetadata<ReqData>[]): Promise<ResData>;
116
116
  }
117
117
  interface Request {
118
118
  name: string;
@@ -132,6 +132,7 @@ interface Job<T = object> {
132
132
  name: string;
133
133
  data: T;
134
134
  expireInSeconds: number;
135
+ signal: AbortSignal;
135
136
  }
136
137
  interface JobWithMetadata<T = object> extends Job<T> {
137
138
  priority: number;
@@ -246,11 +247,11 @@ declare class PgBoss extends EventEmitter<PgBossEventMap> {
246
247
  includeMetadata: true;
247
248
  }): Promise<JobWithMetadata<T>[]>;
248
249
  fetch<T>(name: string, options?: FetchOptions): Promise<Job<T>[]>;
249
- work<ReqData>(name: string, handler: WorkHandler<ReqData>): Promise<string>;
250
- work<ReqData>(name: string, options: WorkOptions & {
250
+ work<ReqData, ResData = any>(name: string, handler: WorkHandler<ReqData, ResData>): Promise<string>;
251
+ work<ReqData, ResData = any>(name: string, options: WorkOptions & {
251
252
  includeMetadata: true;
252
- }, handler: WorkWithMetadataHandler<ReqData>): Promise<string>;
253
- work<ReqData>(name: string, options: WorkOptions, handler: WorkHandler<ReqData>): Promise<string>;
253
+ }, handler: WorkWithMetadataHandler<ReqData, ResData>): Promise<string>;
254
+ work<ReqData, ResData = any>(name: string, options: WorkOptions, handler: WorkHandler<ReqData, ResData>): Promise<string>;
254
255
  offWork(name: string, options?: OffWorkOptions): Promise<void>;
255
256
  notifyWorker(workerId: string): void;
256
257
  subscribe(event: string, name: string): Promise<void>;
package/dist/index.mjs CHANGED
@@ -938,7 +938,6 @@ function checkWorkArgs(name, args) {
938
938
  assert(!("batchSize" in options) || Number.isInteger(options.batchSize) && options.batchSize >= 1, "batchSize must be an integer > 0");
939
939
  assert(!("includeMetadata" in options) || typeof options.includeMetadata === "boolean", "includeMetadata must be a boolean");
940
940
  assert(!("priority" in options) || typeof options.priority === "boolean", "priority must be a boolean");
941
- options.batchSize = options.batchSize || 1;
942
941
  return {
943
942
  options,
944
943
  callback
@@ -950,7 +949,6 @@ function checkFetchArgs(name, options) {
950
949
  assert(!("includeMetadata" in options) || typeof options.includeMetadata === "boolean", "includeMetadata must be a boolean");
951
950
  assert(!("priority" in options) || typeof options.priority === "boolean", "priority must be a boolean");
952
951
  assert(!("ignoreStartAfter" in options) || typeof options.ignoreStartAfter === "boolean", "ignoreStartAfter must be a boolean");
953
- options.batchSize = options.batchSize || 1;
954
952
  }
955
953
  function getConfig(value) {
956
954
  assert(value && (typeof value === "object" || typeof value === "string"), "configuration assert: string or config object is required to connect to postgres");
@@ -1507,8 +1505,8 @@ function unwrapSQLResult(result) {
1507
1505
  if (Array.isArray(result)) return { rows: result.flatMap((i) => i.rows) };
1508
1506
  return result;
1509
1507
  }
1510
- function delay(ms, error) {
1511
- const ac = new AbortController();
1508
+ function delay(ms, error, abortController) {
1509
+ const ac = abortController || new AbortController();
1512
1510
  const promise = new Promise((resolve, reject) => {
1513
1511
  setTimeout(ms, null, { signal: ac.signal }).then(() => {
1514
1512
  if (error) reject(new Error(error));
@@ -1520,8 +1518,8 @@ function delay(ms, error) {
1520
1518
  };
1521
1519
  return promise;
1522
1520
  }
1523
- async function resolveWithinSeconds(promise, seconds, message) {
1524
- const reject = delay(Math.max(1, seconds) * 1e3, message);
1521
+ async function resolveWithinSeconds(promise, seconds, message, abortController) {
1522
+ const reject = delay(Math.max(1, seconds) * 1e3, message, abortController);
1525
1523
  let result;
1526
1524
  try {
1527
1525
  result = await Promise.race([promise, reject]);
@@ -1702,36 +1700,8 @@ var Manager = class extends EventEmitter {
1702
1700
  }
1703
1701
  async work(name, ...args) {
1704
1702
  const { options, callback } = checkWorkArgs(name, args);
1705
- return await this.watch(name, options, callback);
1706
- }
1707
- addWorker(worker) {
1708
- this.workers.set(worker.id, worker);
1709
- }
1710
- removeWorker(worker) {
1711
- this.workers.delete(worker.id);
1712
- }
1713
- getWorkers() {
1714
- return Array.from(this.workers.values());
1715
- }
1716
- emitWip(name) {
1717
- if (!INTERNAL_QUEUES[name]) {
1718
- const now = Date.now();
1719
- if (now - this.wipTs > 2e3) {
1720
- this.emit(events$2.wip, this.getWipData());
1721
- this.wipTs = now;
1722
- }
1723
- }
1724
- }
1725
- getWipData(options = {}) {
1726
- const { includeInternal = false } = options;
1727
- return this.getWorkers().map((i) => i.toWipData()).filter((i) => i.state !== "stopped" && (!INTERNAL_QUEUES[i.name] || includeInternal));
1728
- }
1729
- hasPendingCleanups() {
1730
- return this.pendingOffWorkCleanups.size > 0;
1731
- }
1732
- async watch(name, options, callback) {
1733
1703
  if (this.stopped) throw new Error("Workers are disabled. pg-boss is stopped");
1734
- const { pollingInterval: interval, batchSize, includeMetadata = false, priority = true } = options;
1704
+ const { pollingInterval: interval, batchSize = 1, includeMetadata = false, priority = true } = options;
1735
1705
  const id = randomUUID({ disableEntropyCache: true });
1736
1706
  const fetch = () => this.fetch(name, {
1737
1707
  batchSize,
@@ -1744,8 +1714,12 @@ var Manager = class extends EventEmitter {
1744
1714
  this.emitWip(name);
1745
1715
  const maxExpiration = jobs.reduce((acc, i) => Math.max(acc, i.expireInSeconds), 0);
1746
1716
  const jobIds = jobs.map((job) => job.id);
1717
+ const ac = new AbortController();
1718
+ jobs.forEach((job) => {
1719
+ job.signal = ac.signal;
1720
+ });
1747
1721
  try {
1748
- const result = await resolveWithinSeconds(callback(jobs), maxExpiration, `handler execution exceeded ${maxExpiration}s`);
1722
+ const result = await resolveWithinSeconds(callback(jobs), maxExpiration, `handler execution exceeded ${maxExpiration}s`, ac);
1749
1723
  await this.complete(name, jobIds, jobIds.length === 1 ? result : void 0);
1750
1724
  } catch (err) {
1751
1725
  await this.fail(name, jobIds, err);
@@ -1774,6 +1748,31 @@ var Manager = class extends EventEmitter {
1774
1748
  worker.start();
1775
1749
  return id;
1776
1750
  }
1751
+ addWorker(worker) {
1752
+ this.workers.set(worker.id, worker);
1753
+ }
1754
+ removeWorker(worker) {
1755
+ this.workers.delete(worker.id);
1756
+ }
1757
+ getWorkers() {
1758
+ return Array.from(this.workers.values());
1759
+ }
1760
+ emitWip(name) {
1761
+ if (!INTERNAL_QUEUES[name]) {
1762
+ const now = Date.now();
1763
+ if (now - this.wipTs > 2e3) {
1764
+ this.emit(events$2.wip, this.getWipData());
1765
+ this.wipTs = now;
1766
+ }
1767
+ }
1768
+ }
1769
+ getWipData(options = {}) {
1770
+ const { includeInternal = false } = options;
1771
+ return this.getWorkers().map((i) => i.toWipData()).filter((i) => i.state !== "stopped" && (!INTERNAL_QUEUES[i.name] || includeInternal));
1772
+ }
1773
+ hasPendingCleanups() {
1774
+ return this.pendingOffWorkCleanups.size > 0;
1775
+ }
1777
1776
  async offWork(name, options = { wait: true }) {
1778
1777
  assert(name, "queue name is required");
1779
1778
  assert(typeof name === "string", "queue name must be a string");
@@ -1918,7 +1917,7 @@ var Manager = class extends EventEmitter {
1918
1917
  table,
1919
1918
  name,
1920
1919
  policy,
1921
- limit: options.batchSize,
1920
+ limit: options.batchSize || 1,
1922
1921
  ignoreSingletons: singletonsActive
1923
1922
  };
1924
1923
  const sql = fetchNextJob(fetchOptions);
@@ -2011,15 +2010,18 @@ var Manager = class extends EventEmitter {
2011
2010
  async createQueue(name, options = {}) {
2012
2011
  name = name || options.name;
2013
2012
  assertQueueName(name);
2014
- options.policy = options.policy || QUEUE_POLICIES.standard;
2015
- assert(options.policy in QUEUE_POLICIES, `${options.policy} is not a valid queue policy`);
2013
+ const policy = options.policy || QUEUE_POLICIES.standard;
2014
+ assert(policy in QUEUE_POLICIES, `${policy} is not a valid queue policy`);
2016
2015
  validateQueueArgs(options);
2017
2016
  if (options.deadLetter) {
2018
2017
  assertQueueName(options.deadLetter);
2019
2018
  notStrictEqual(name, options.deadLetter, "deadLetter cannot be itself");
2020
2019
  await this.getQueueCache(options.deadLetter);
2021
2020
  }
2022
- const sql = createQueue(this.config.schema, name, options);
2021
+ const sql = createQueue(this.config.schema, name, {
2022
+ ...options,
2023
+ policy
2024
+ });
2023
2025
  await this.db.executeSql(sql);
2024
2026
  }
2025
2027
  async getQueues(names) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pg-boss",
3
- "version": "12.3.1",
3
+ "version": "12.4.0",
4
4
  "description": "Queueing jobs in Postgres from Node.js like a boss",
5
5
  "type": "module",
6
6
  "main": "./dist/index.mjs",