From e4310455daeb491e206275029fd23b7626274da3 Mon Sep 17 00:00:00 2001 From: Marcus Reinhardt Date: Tue, 29 Oct 2024 13:23:45 +0100 Subject: [PATCH] support custom key in `queue.enqueue` even when `runAt` is not specified --- .env.example | 7 +++++++ package.json | 6 ++++-- pnpm-lock.yaml | 31 +++++++++++++++++++++++++++++++ src/PrismaQueue.spec.ts | 15 +++++++++++++++ src/PrismaQueue.ts | 6 +++--- 5 files changed, 60 insertions(+), 5 deletions(-) create mode 100644 .env.example diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..64ebdc7 --- /dev/null +++ b/.env.example @@ -0,0 +1,7 @@ +DATABASE_ENGINE="postgres" +DATABASE_HOST="localhost" +DATABASE_PORT=5432 +DATABASE_USERNAME="postgres" +DATABASE_PASSWORD="postgres" +DATABASE_DBNAME="prisma_queue" +DATABASE_URL=${DATABASE_ENGINE}://${DATABASE_USERNAME}:${DATABASE_PASSWORD}@${DATABASE_HOST}:${DATABASE_PORT}/${DATABASE_DBNAME} \ No newline at end of file diff --git a/package.json b/package.json index 0bfff91..5877e81 100644 --- a/package.json +++ b/package.json @@ -39,7 +39,8 @@ "test": "npm run lint && npm run prettycheck && npm run typecheck && npm run spec", "prepare": "prisma generate", "reset": "prisma db push --force-reset && prisma generate", - "prepublishOnly": "npm run build" + "prepublishOnly": "npm run build", + "with-env": "dotenv -e ./.env --" }, "dependencies": { "croner": "^8.0.2", @@ -63,6 +64,7 @@ "tsx": "^4.15.7", "typescript": "^5.5.2", "vite-tsconfig-paths": "^4.3.2", - "vitest": "^1.6.0" + "vitest": "^1.6.0", + "dotenv-cli": "^7.4.2" } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 2e30fe9..ac22799 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -33,6 +33,9 @@ importers: '@types/node': specifier: ^20.14.9 version: 20.14.9 + dotenv-cli: + specifier: ^7.4.2 + version: 7.4.2 eslint: specifier: ^8.57.0 version: 8.57.0 @@ -832,6 +835,18 @@ packages: resolution: {integrity: sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==} engines: {node: '>=6.0.0'} + dotenv-cli@7.4.2: + resolution: {integrity: sha512-SbUj8l61zIbzyhIbg0FwPJq6+wjbzdn9oEtozQpZ6kW2ihCcapKVZj49oCT3oPM+mgQm+itgvUQcG5szxVrZTA==} + hasBin: true + + dotenv-expand@10.0.0: + resolution: {integrity: sha512-GopVGCpVS1UKH75VKHGuQFqS1Gusej0z4FyQkPdwjil2gNIv+LNsqBlboOzpJFZKVT95GkCyWJbBSdFEFUWI2A==} + engines: {node: '>=12'} + + dotenv@16.4.5: + resolution: {integrity: sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg==} + engines: {node: '>=12'} + esbuild@0.19.10: resolution: {integrity: sha512-S1Y27QGt/snkNYrRcswgRFqZjaTG5a5xM3EQo97uNBnH505pdzSNe/HLBq1v0RO7iK/ngdbhJB6mDAp0OK+iUA==} engines: {node: '>=12'} @@ -1200,6 +1215,9 @@ packages: resolution: {integrity: sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==} engines: {node: '>=16 || 14 >=14.17'} + minimist@1.2.8: + resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} + mlly@1.4.2: resolution: {integrity: sha512-i/Ykufi2t1EZ6NaPLdfnZk2AX8cs0d+mTzVKuPfqPKPatxLApaBoxJQ9x1/uckXtrS/U5oisPMDkNs0yQTaBRg==} @@ -2366,6 +2384,17 @@ snapshots: dependencies: esutils: 2.0.3 + dotenv-cli@7.4.2: + dependencies: + cross-spawn: 7.0.3 + dotenv: 16.4.5 + dotenv-expand: 10.0.0 + minimist: 1.2.8 + + dotenv-expand@10.0.0: {} + + dotenv@16.4.5: {} + esbuild@0.19.10: optionalDependencies: '@esbuild/aix-ppc64': 0.19.10 @@ -2790,6 +2819,8 @@ snapshots: dependencies: brace-expansion: 2.0.1 + minimist@1.2.8: {} + mlly@1.4.2: dependencies: acorn: 8.10.0 diff --git a/src/PrismaQueue.spec.ts b/src/PrismaQueue.spec.ts index c0e5522..2da0238 100644 --- a/src/PrismaQueue.spec.ts +++ b/src/PrismaQueue.spec.ts @@ -54,9 +54,24 @@ describe("PrismaQueue", () => { ] `); const record = await job.fetch(); + expect(record.key).toBeNull(); expect(record?.payload).toEqual({ email: "foo@bar.com" }); expect(record?.runAt).toBeInstanceOf(Date); }); + + it("should properly enqueue a job with a custom key", async () => { + const job = await queue.enqueue({ email: "foo@bar.com" }, { key: "custom-key" }); + expect(job).toBeInstanceOf(PrismaJob); + expect(Object.keys(job)).toMatchInlineSnapshot(` + [ + "id", + ] + `); + const record = await job.fetch(); + expect(record?.payload).toEqual({ email: "foo@bar.com" }); + expect(record?.runAt).toBeInstanceOf(Date); + expect(record.key).toBe("custom-key"); + }); }); describe("schedule", () => { diff --git a/src/PrismaQueue.ts b/src/PrismaQueue.ts index e88b9ed..cdfc771 100644 --- a/src/PrismaQueue.ts +++ b/src/PrismaQueue.ts @@ -176,11 +176,11 @@ export class PrismaQueue< ): Promise> { debug(`enqueue`, this.name, payloadOrFunction, options); const { name: queueName, config } = this; - const { key, cron = null, maxAttempts = config.maxAttempts, priority = 0, runAt } = options; + const { key = null, cron = null, maxAttempts = config.maxAttempts, priority = 0, runAt } = options; const record = await this.#prisma.$transaction(async (client) => { const payload = payloadOrFunction instanceof Function ? await payloadOrFunction(client) : payloadOrFunction; - const data = { queue: queueName, cron, payload, maxAttempts, priority }; + const data = { queue: queueName, cron, payload, maxAttempts, priority, key }; if (key && runAt) { const { count } = await this.model.deleteMany({ where: { @@ -198,7 +198,7 @@ export class PrismaQueue< const update = { ...data, ...(runAt ? { runAt } : {}) }; return await this.model.upsert({ where: { key_runAt: { key, runAt } }, - create: { key, ...update }, + create: { ...update }, update, }); }