diff --git a/package.json b/package.json index 70409f0..41f21ca 100644 --- a/package.json +++ b/package.json @@ -80,7 +80,7 @@ "semantic-release": "^24.2.7", "tailwindcss": "^4.1.13", "tsx": "^4.20.5", - "turbo": "^2.5.8", + "turbo": "^2.8.3", "typescript": "^5.9.2", "typescript-eslint": "^8.42.0", "vitepress": "^1.6.4", diff --git a/packages/backends/backend-test/src/claimPendingJob.ts b/packages/backends/backend-test/src/claimPendingJob.ts index 3a7622f..a963fce 100644 --- a/packages/backends/backend-test/src/claimPendingJob.ts +++ b/packages/backends/backend-test/src/claimPendingJob.ts @@ -170,5 +170,28 @@ export default function defineClaimPendingJobTestSuite() { const [claimedJob] = await backend.claimPendingJob("default"); expect(claimedJob).toBe(undefined); }); + + it("should claim at max 1 job", async () => { + // Insert a new waiting job + const job: NewJobData = { + queue: "default", + class: "TestJob", + args: [{ foo: "bar" }], + constructor_args: [{}], + state: "waiting", + script: "test.js", + attempt: 0, + max_attempts: 5, + }; + + await backend.createNewJob(job); + await backend.createNewJob(job); + await backend.createNewJob(job); + await backend.createNewJob(job); + await backend.createNewJob(job); + + const claimedJobs = await backend.claimPendingJob("default", 1); + expect(claimedJobs).toHaveLength(1); + }); }); } diff --git a/packages/backends/sqlite/package.json b/packages/backends/sqlite/package.json index e0441e0..515dc48 100644 --- a/packages/backends/sqlite/package.json +++ b/packages/backends/sqlite/package.json @@ -45,7 +45,7 @@ "dependencies": { "@sidequest/backend": "workspace:*", "@sidequest/core": "workspace:*", - "better-sqlite3": "^12.4.1", + "better-sqlite3": "^12.6.2", "knex": "^3.1.0" }, "devDependencies": { diff --git a/packages/backends/sqlite/src/sqlite-backend.ts b/packages/backends/sqlite/src/sqlite-backend.ts index 05afa3a..057b23e 100644 --- a/packages/backends/sqlite/src/sqlite-backend.ts +++ b/packages/backends/sqlite/src/sqlite-backend.ts @@ -48,20 +48,31 @@ export default class SqliteBackend extends SQLBackend { async claimPendingJob(queue: string, quantity = 1): Promise { const workerName = `sidequest@${hostname()}-${process.pid}`; - const result = (await this.knex.transaction(async (trx) => - trx("sidequest_jobs") - .update({ - claimed_by: workerName, - claimed_at: new Date(), - state: "claimed", - }) - .where("state", "waiting") - .andWhere("queue", queue) - .andWhere("available_at", "<=", new Date()) - .orderBy("inserted_at") - .limit(quantity) - .returning("*"), - )) as JobData[]; + const rowsToUpdate = (await this.knex("sidequest_jobs") + .select("id") + .where("state", "waiting") + .andWhere("queue", queue) + .andWhere("available_at", "<=", new Date()) + .orderBy("inserted_at") + .limit(quantity)) as { id: number }[]; + + if (rowsToUpdate.length === 0) { + return []; + } + + const result = (await this.knex("sidequest_jobs") + .update({ + claimed_by: workerName, + claimed_at: new Date(), + state: "claimed", + }) + .where("state", "waiting") + .andWhere( + "id", + "in", + rowsToUpdate.map((row) => row.id), + ) + .returning("*")) as JobData[]; return result.map(safeParseJobData); } diff --git a/yarn.lock b/yarn.lock index eded6bc..77224f7 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2727,7 +2727,7 @@ __metadata: "@sidequest/backend": "workspace:*" "@sidequest/backend-test": "workspace:*" "@sidequest/core": "workspace:*" - better-sqlite3: "npm:^12.4.1" + better-sqlite3: "npm:^12.6.2" knex: "npm:^3.1.0" languageName: unknown linkType: soft @@ -4080,14 +4080,14 @@ __metadata: languageName: node linkType: hard -"better-sqlite3@npm:^12.4.1": - version: 12.4.1 - resolution: "better-sqlite3@npm:12.4.1" +"better-sqlite3@npm:^12.6.2": + version: 12.6.2 + resolution: "better-sqlite3@npm:12.6.2" dependencies: bindings: "npm:^1.5.0" node-gyp: "npm:latest" prebuild-install: "npm:^7.1.1" - checksum: 10c0/88773a75d996b4171e5690a38459b05dc814a792701b224bd9909ee084dc0b4c64aaffbdbcf4bbbc6d4e247faf19e91b2a56cf4175d746d3bd9ff14764eb05aa + checksum: 10c0/a58fb3f7a7f5469ba0b8de0855aa67396ff34f951a6975746e4b21987f530be6a34427d1d4bd5958cf48c67ed7ba1df038ae163d2ee9d944237f6b8112f6640d languageName: node linkType: hard @@ -11102,7 +11102,7 @@ __metadata: semantic-release: "npm:^24.2.7" tailwindcss: "npm:^4.1.13" tsx: "npm:^4.20.5" - turbo: "npm:^2.5.8" + turbo: "npm:^2.8.3" typescript: "npm:^5.9.2" typescript-eslint: "npm:^8.42.0" vitepress: "npm:^1.6.4" @@ -11987,58 +11987,58 @@ __metadata: languageName: node linkType: hard -"turbo-darwin-64@npm:2.5.8": - version: 2.5.8 - resolution: "turbo-darwin-64@npm:2.5.8" +"turbo-darwin-64@npm:2.8.3": + version: 2.8.3 + resolution: "turbo-darwin-64@npm:2.8.3" conditions: os=darwin & cpu=x64 languageName: node linkType: hard -"turbo-darwin-arm64@npm:2.5.8": - version: 2.5.8 - resolution: "turbo-darwin-arm64@npm:2.5.8" +"turbo-darwin-arm64@npm:2.8.3": + version: 2.8.3 + resolution: "turbo-darwin-arm64@npm:2.8.3" conditions: os=darwin & cpu=arm64 languageName: node linkType: hard -"turbo-linux-64@npm:2.5.8": - version: 2.5.8 - resolution: "turbo-linux-64@npm:2.5.8" +"turbo-linux-64@npm:2.8.3": + version: 2.8.3 + resolution: "turbo-linux-64@npm:2.8.3" conditions: os=linux & cpu=x64 languageName: node linkType: hard -"turbo-linux-arm64@npm:2.5.8": - version: 2.5.8 - resolution: "turbo-linux-arm64@npm:2.5.8" +"turbo-linux-arm64@npm:2.8.3": + version: 2.8.3 + resolution: "turbo-linux-arm64@npm:2.8.3" conditions: os=linux & cpu=arm64 languageName: node linkType: hard -"turbo-windows-64@npm:2.5.8": - version: 2.5.8 - resolution: "turbo-windows-64@npm:2.5.8" +"turbo-windows-64@npm:2.8.3": + version: 2.8.3 + resolution: "turbo-windows-64@npm:2.8.3" conditions: os=win32 & cpu=x64 languageName: node linkType: hard -"turbo-windows-arm64@npm:2.5.8": - version: 2.5.8 - resolution: "turbo-windows-arm64@npm:2.5.8" +"turbo-windows-arm64@npm:2.8.3": + version: 2.8.3 + resolution: "turbo-windows-arm64@npm:2.8.3" conditions: os=win32 & cpu=arm64 languageName: node linkType: hard -"turbo@npm:^2.5.8": - version: 2.5.8 - resolution: "turbo@npm:2.5.8" +"turbo@npm:^2.8.3": + version: 2.8.3 + resolution: "turbo@npm:2.8.3" dependencies: - turbo-darwin-64: "npm:2.5.8" - turbo-darwin-arm64: "npm:2.5.8" - turbo-linux-64: "npm:2.5.8" - turbo-linux-arm64: "npm:2.5.8" - turbo-windows-64: "npm:2.5.8" - turbo-windows-arm64: "npm:2.5.8" + turbo-darwin-64: "npm:2.8.3" + turbo-darwin-arm64: "npm:2.8.3" + turbo-linux-64: "npm:2.8.3" + turbo-linux-arm64: "npm:2.8.3" + turbo-windows-64: "npm:2.8.3" + turbo-windows-arm64: "npm:2.8.3" dependenciesMeta: turbo-darwin-64: optional: true @@ -12054,7 +12054,7 @@ __metadata: optional: true bin: turbo: bin/turbo - checksum: 10c0/34e8dc87fc2c5d63c3cd5aede9068c1123509d88f9bb99283ffec1687de6ad6df7ebfb83a5d348580afb3fdac53af479456e36938a1b6ed80fc1c3416c6dc3f3 + checksum: 10c0/eae8698697505de4df29e3aea7ac60b7a7a018cfe7b26f30131664a11d7a64ec2cca3fe4a0c91439d8ad583c266531f10620d31baad5a072550115f74bf041a0 languageName: node linkType: hard