diff --git a/package-lock.json b/package-lock.json index 27adbd9..69eb2fa 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "pg-boss", - "version": "10.0.2", + "version": "10.0.3", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "pg-boss", - "version": "10.0.2", + "version": "10.0.3", "license": "MIT", "dependencies": { "cron-parser": "^4.0.0", @@ -51,9 +51,9 @@ } }, "node_modules/@babel/compat-data": { - "version": "7.25.2", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.25.2.tgz", - "integrity": "sha512-bYcppcpKBvX4znYaPEeFau03bp89ShqNMLs+rmdptMw+heSZh9+z84d2YG+K7cYLbWwzdjtDoW/uqZmPjulClQ==", + "version": "7.25.4", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.25.4.tgz", + "integrity": "sha512-+LGRog6RAsCJrrrg/IO6LGmpphNe5DiK30dGjCoxxeGv49B10/3XYGxPsAwrDlMFcFEvdAUavDT8r9k/hSyQqQ==", "dev": true, "engines": { "node": ">=6.9.0" @@ -105,12 +105,12 @@ } }, "node_modules/@babel/generator": { - "version": "7.25.0", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.25.0.tgz", - "integrity": "sha512-3LEEcj3PVW8pW2R1SR1M89g/qrYk/m/mB/tLqn7dn4sbBUQyTqnlod+II2U4dqiGtUmkcnAmkMDralTFZttRiw==", + "version": "7.25.5", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.25.5.tgz", + "integrity": "sha512-abd43wyLfbWoxC6ahM8xTkqLpGB2iWBVyuKC9/srhFunCd1SDNrV1s72bBpK4hLj8KLzHBBcOblvLQZBNw9r3w==", "dev": true, "dependencies": { - "@babel/types": "^7.25.0", + "@babel/types": "^7.25.4", "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.25", "jsesc": "^2.5.1" @@ -315,12 +315,12 @@ } }, "node_modules/@babel/parser": { - "version": "7.25.3", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.25.3.tgz", - "integrity": "sha512-iLTJKDbJ4hMvFPgQwwsVoxtHyWpKKPBrxkANrSYewDPaPpT5py5yeVkgPIJ7XYXhndxJpaA3PyALSXQ7u8e/Dw==", + "version": "7.25.4", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.25.4.tgz", + "integrity": "sha512-nq+eWrOgdtu3jG5Os4TQP3x3cLA8hR8TvJNjD8vnPa20WGycimcparWnLK4jJhElTK6SDyuJo1weMKO/5LpmLA==", "dev": true, "dependencies": { - "@babel/types": "^7.25.2" + "@babel/types": "^7.25.4" }, "bin": { "parser": "bin/babel-parser.js" @@ -344,16 +344,16 @@ } }, "node_modules/@babel/traverse": { - "version": "7.25.3", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.25.3.tgz", - "integrity": "sha512-HefgyP1x754oGCsKmV5reSmtV7IXj/kpaE1XYY+D9G5PvKKoFfSbiS4M77MdjuwlZKDIKFCffq9rPU+H/s3ZdQ==", + "version": "7.25.4", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.25.4.tgz", + "integrity": "sha512-VJ4XsrD+nOvlXyLzmLzUs/0qjFS4sK30te5yEFlvbbUNEgKaVb2BHZUpAL+ttLPQAHNrsI3zZisbfha5Cvr8vg==", "dev": true, "dependencies": { "@babel/code-frame": "^7.24.7", - "@babel/generator": "^7.25.0", - "@babel/parser": "^7.25.3", + "@babel/generator": "^7.25.4", + "@babel/parser": "^7.25.4", "@babel/template": "^7.25.0", - "@babel/types": "^7.25.2", + "@babel/types": "^7.25.4", "debug": "^4.3.1", "globals": "^11.1.0" }, @@ -362,9 +362,9 @@ } }, "node_modules/@babel/types": { - "version": "7.25.2", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.25.2.tgz", - "integrity": "sha512-YTnYtra7W9e6/oAZEHj0bJehPRUlLH9/fbpT5LfB0NhQXyALCRkRs3zH9v07IYhkgpqX6Z78FnuccZr/l4Fs4Q==", + "version": "7.25.4", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.25.4.tgz", + "integrity": "sha512-zQ1ijeeCXVEh+aNL0RlmkPkG8HUiDcU2pzQQFjtbntgAczRASFzj4H+6+bV+dy1ntKR14I/DypeuRG1uma98iQ==", "dev": true, "dependencies": { "@babel/helper-string-parser": "^7.24.8", @@ -726,9 +726,9 @@ "dev": true }, "node_modules/@types/node": { - "version": "20.16.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.16.0.tgz", - "integrity": "sha512-vDxceJcoZhIVh67S568bm1UGZO0DX0hpplJZxzeXMKwIPLn190ec5RRxQ69BKhX44SUGIxxgMdDY557lGLKprQ==", + "version": "20.16.1", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.16.1.tgz", + "integrity": "sha512-zJDo7wEadFtSyNz5QITDfRcrhqDvQI1xQNQ0VoizPjM/dVAODqqIUWbJPkvsxmTI0MYRGRikcdjMPhOssnPejQ==", "dev": true, "dependencies": { "undici-types": "~6.19.2" @@ -1164,9 +1164,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001651", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001651.tgz", - "integrity": "sha512-9Cf+Xv1jJNe1xPZLGuUXLNkE1BoDkqRqYyFJ9TDYSqhduqA4hu4oR9HluGoWYQC/aj8WHjsGVV+bwkh0+tegRg==", + "version": "1.0.30001653", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001653.tgz", + "integrity": "sha512-XGWQVB8wFQ2+9NZwZ10GxTYC5hk0Fa+q8cSkr0tgvMhYhMHP/QC+WTgrePMDBWiWc/pV+1ik82Al20XOK25Gcw==", "dev": true, "funding": [ { @@ -1476,9 +1476,9 @@ } }, "node_modules/electron-to-chromium": { - "version": "1.5.11", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.11.tgz", - "integrity": "sha512-R1CccCDYqndR25CaXFd6hp/u9RaaMcftMkphmvuepXr5b1vfLkRml6aWVeBhXJ7rbevHkKEMJtz8XqPf7ffmew==", + "version": "1.5.13", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.13.tgz", + "integrity": "sha512-lbBcvtIJ4J6sS4tb5TLp1b4LyfCdMkwStzXPyAgVgTRAsep4bvrAGaBOP7ZJtQMNJpSQ9SqG4brWOroNaQtm7Q==", "dev": true }, "node_modules/emoji-regex": { @@ -1810,9 +1810,9 @@ } }, "node_modules/eslint-module-utils": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.8.1.tgz", - "integrity": "sha512-rXDXR3h7cs7dy9RNpUlQf80nX31XWJEyGq1tRMo+6GsO5VmTe4UTwtmonAD4ZkAsrfMVDA2wlGJ3790Ys+D49Q==", + "version": "2.8.2", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.8.2.tgz", + "integrity": "sha512-3XnC5fDyc8M4J2E8pt8pmSVRX2M+5yWMCfI/kDZwauQeFgzQOuhcRBFKjTeJagqgk4sFKxe1mvNVnaWwImx/Tg==", "dev": true, "dependencies": { "debug": "^3.2.7" @@ -2955,9 +2955,9 @@ } }, "node_modules/is-core-module": { - "version": "2.15.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.15.0.tgz", - "integrity": "sha512-Dd+Lb2/zvk9SKy1TGCt1wFJFo/MWBPMX5x7KcvLajWTGuomczdQX61PvY5yK6SVACwpoexWo81IfFyoKY2QnTA==", + "version": "2.15.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.15.1.tgz", + "integrity": "sha512-z0vtXSwucUJtANQWldhbtbt7BnL0vxiFjIdDLAatwhDYty2bad6s+rijD6Ri4YuYJubLzIJLUidCh09e1djEVQ==", "dev": true, "dependencies": { "hasown": "^2.0.2" @@ -5486,9 +5486,9 @@ } }, "node_modules/undici-types": { - "version": "6.19.6", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.6.tgz", - "integrity": "sha512-e/vggGopEfTKSvj4ihnOLTsqhrKRN3LeO6qSN/GxohhuRv8qH9bNQ4B8W7e/vFL+0XTnmHPB4/kegunZGA4Org==", + "version": "6.19.8", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz", + "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==", "dev": true }, "node_modules/update-browserslist-db": { diff --git a/package.json b/package.json index 1737bbc..06bec81 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "pg-boss", - "version": "10.0.2", + "version": "10.0.3", "description": "Queueing jobs in Postgres from Node.js like a boss", "main": "./src/index.js", "engines": { diff --git a/src/attorney.js b/src/attorney.js index 2d1d1bc..9f51cdd 100644 --- a/src/attorney.js +++ b/src/attorney.js @@ -1,7 +1,13 @@ const assert = require('assert') const { DEFAULT_SCHEMA } = require('./plans') +const POLICY = { + MAX_EXPIRATION_HOURS: 24, + MIN_POLLING_INTERVAL_MS: 500 +} + module.exports = { + POLICY, getConfig, checkSendArgs, checkQueueArgs, @@ -12,8 +18,6 @@ module.exports = { assertQueueName } -const MAX_INTERVAL_HOURS = 24 - const WARNINGS = { CLOCK_SKEW: { message: 'Timekeeper detected clock skew between this instance and the database server. This will not affect scheduling operations, but this warning is shown any time the skew exceeds 60 seconds.', @@ -262,7 +266,7 @@ function applyExpirationConfig (config, defaults = {}) { ? config.expireInSeconds : null - assert(!expireIn || expireIn / 60 / 60 < MAX_INTERVAL_HOURS, `configuration assert: expiration cannot exceed ${MAX_INTERVAL_HOURS} hours`) + assert(!expireIn || expireIn / 60 / 60 < POLICY.MAX_EXPIRATION_HOURS, `configuration assert: expiration cannot exceed ${POLICY.MAX_EXPIRATION_HOURS} hours`) config.expireIn = expireIn config.expireInDefault = defaults?.expireIn @@ -279,8 +283,8 @@ function applyRetryConfig (config, defaults) { } function applyPollingInterval (config, defaults) { - assert(!('pollingIntervalSeconds' in config) || config.pollingIntervalSeconds >= 0.5, - 'configuration assert: pollingIntervalSeconds must be at least every 500ms') + assert(!('pollingIntervalSeconds' in config) || config.pollingIntervalSeconds >= POLICY.MIN_POLLING_INTERVAL_MS / 1000, + `configuration assert: pollingIntervalSeconds must be at least every ${POLICY.MIN_POLLING_INTERVAL_MS}ms`) config.pollingInterval = ('pollingIntervalSeconds' in config) ? config.pollingIntervalSeconds * 1000 @@ -300,7 +304,8 @@ function applyMaintenanceConfig (config) { ? config.maintenanceIntervalSeconds : 120 - assert(config.maintenanceIntervalSeconds / 60 / 60 < MAX_INTERVAL_HOURS, `configuration assert: maintenance interval cannot exceed ${MAX_INTERVAL_HOURS} hours`) + assert(config.maintenanceIntervalSeconds / 60 / 60 < POLICY.MAX_EXPIRATION_HOURS, + `configuration assert: maintenance interval cannot exceed ${POLICY.MAX_EXPIRATION_HOURS} hours`) } function applyDeleteConfig (config) { @@ -344,7 +349,8 @@ function applyMonitoringConfig (config) { : null if (config.monitorStateIntervalSeconds) { - assert(config.monitorStateIntervalSeconds / 60 / 60 < MAX_INTERVAL_HOURS, `configuration assert: state monitoring interval cannot exceed ${MAX_INTERVAL_HOURS} hours`) + assert(config.monitorStateIntervalSeconds / 60 / 60 < POLICY.MAX_EXPIRATION_HOURS, + `configuration assert: state monitoring interval cannot exceed ${POLICY.MAX_EXPIRATION_HOURS} hours`) } const TEN_MINUTES_IN_SECONDS = 600 diff --git a/src/plans.js b/src/plans.js index 548bc8d..24f3a85 100644 --- a/src/plans.js +++ b/src/plans.js @@ -499,7 +499,7 @@ function fetchNextJob (schema) { WHERE name = $1 AND state < '${JOB_STATES.active}' AND start_after < now() - ORDER BY ${priority && 'priority desc, '} created_on, id + ORDER BY ${priority ? 'priority desc, ' : ''}created_on, id LIMIT $2 FOR UPDATE SKIP LOCKED ) diff --git a/src/worker.js b/src/worker.js index d245c39..4f35354 100644 --- a/src/worker.js +++ b/src/worker.js @@ -74,7 +74,7 @@ class Worker { this.lastJobDuration = duration - if (!this.stopping && !this.beenNotified && (this.interval - duration > 500)) { + if (!this.stopping && !this.beenNotified && (this.interval - duration) > 100) { this.loopDelayPromise = delay(this.interval - duration) await this.loopDelayPromise this.loopDelayPromise = null diff --git a/test/priorityTest.js b/test/priorityTest.js index 6681d24..231c05a 100644 --- a/test/priorityTest.js +++ b/test/priorityTest.js @@ -31,4 +31,21 @@ describe('priority', function () { assert.strictEqual(job2.id, medium) assert.strictEqual(job3.id, low) }) + + it('bypasses priority when priority option used in fetch', async function () { + const boss = this.test.boss = await helper.start({ ...this.test.bossConfig }) + const queue = this.test.bossConfig.schema + + const low = await boss.send(queue, null, { priority: 1 }) + const medium = await boss.send(queue, null, { priority: 5 }) + const high = await boss.send(queue, null, { priority: 10 }) + + const [job1] = await boss.fetch(queue, { priority: false }) + const [job2] = await boss.fetch(queue, { priority: false }) + const [job3] = await boss.fetch(queue, { priority: false }) + + assert.strictEqual(job1.id, low) + assert.strictEqual(job2.id, medium) + assert.strictEqual(job3.id, high) + }) })