The docs state that jobs added to the same named queue run "in series", "one at a time". With worker.localQueue enabled they run concurrently — per-queue concurrency becomes min(localQueue.size, concurrentJobs) instead of 1. A single worker pool is enough to trigger it.
Nothing errors, retries or logs; every job reports success. An application relying on that guarantee to serialise read-modify-write work will silently lose writes.
Reproduced on 0.17.3 and on main (cea9d60).
Reproduction
docker run -d --name gw-repro-pg -e POSTGRES_PASSWORD=postgres \
-e POSTGRES_DB=gwrepro -p 54329:5432 postgres:16-alpine
npm init -y && npm i graphile-worker@0.17.3
node repro.js
const { run, makeWorkerUtils } = require("graphile-worker");
const connectionString =
process.env.DATABASE_URL ||
"postgres://postgres:postgres@localhost:54329/gwrepro";
const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
(async () => {
const utils = await makeWorkerUtils({ connectionString });
await utils.migrate();
// A backlog of 12 jobs, all on ONE named queue.
for (let i = 1; i <= 12; i++) {
await utils.addJob("t", { i }, { queueName: "my-queue" });
}
let active = 0;
let maxActive = 0;
const runner = await run({
preset: {
worker: {
connectionString,
concurrentJobs: 4,
localQueue: { size: 5 }, // <-- remove this line and maxActive is 1
},
},
taskList: {
t: async () => {
active++;
if (active > maxActive) maxActive = active;
await sleep(200);
active--;
},
},
});
while (
(
await utils.withPgClient((c) =>
c.query("select 1 from graphile_worker._private_jobs limit 1"),
)
).rowCount
) {
await sleep(50);
}
await runner.stop();
await utils.release();
console.log(`jobs from one named queue running at once: ${maxActive}`);
console.log(`expected per the docs: 1`);
})();
jobs from one named queue running at once: 4
expected per the docs: 1
Remove the one localQueue line and the same script prints 1.
size: 5 is concurrentJobs + 1, the value recommended in docs/performance. size: 2 breaks it too; concurrentJobs: 1 with size: 16 does not.
Environment
|
|
| graphile-worker |
0.17.3 (npm latest), and main @ cea9d60 built from source |
| Node |
v24.5.0 |
| Postgres |
16.14 |
The docs state that jobs added to the same named queue run "in series", "one at a time". With
worker.localQueueenabled they run concurrently — per-queue concurrency becomesmin(localQueue.size, concurrentJobs)instead of1. A single worker pool is enough to trigger it.Nothing errors, retries or logs; every job reports success. An application relying on that guarantee to serialise read-modify-write work will silently lose writes.
Reproduced on
0.17.3and onmain(cea9d60).Reproduction
docker run -d --name gw-repro-pg -e POSTGRES_PASSWORD=postgres \ -e POSTGRES_DB=gwrepro -p 54329:5432 postgres:16-alpine npm init -y && npm i graphile-worker@0.17.3 node repro.jsRemove the one
localQueueline and the same script prints1.size: 5isconcurrentJobs + 1, the value recommended in docs/performance.size: 2breaks it too;concurrentJobs: 1withsize: 16does not.Environment
0.17.3(npmlatest), andmain@cea9d60built from sourcev24.5.016.14