@boringnode/queue 0.0.1-alpha → 0.0.1-alpha.1

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.
@@ -1,34 +1,102 @@
1
1
  // src/drivers/redis_adapter.ts
2
- import { VerrouLeaseManager } from "#lease_managers/verrou";
3
2
  import { Redis } from "ioredis";
4
3
  var redisKey = "jobs";
5
- var PROCESS_DELAYED_JOBS_SCRIPT = `
6
- local delayed_key = KEYS[1]
7
- local queue_key = KEYS[2]
8
- local now = ARGV[1]
4
+ var ACQUIRE_JOB_SCRIPT = `
5
+ local pending_key = KEYS[1]
6
+ local active_key = KEYS[2]
7
+ local delayed_key = KEYS[3]
8
+ local worker_id = ARGV[1]
9
+ local now = ARGV[2]
9
10
 
10
- -- Get ready jobs (score <= now)
11
+ -- First, process delayed jobs
11
12
  local ready_jobs = redis.call('ZRANGEBYSCORE', delayed_key, 0, now)
12
-
13
13
  if #ready_jobs > 0 then
14
- -- Move jobs to priority queue and remove from delayed queue atomically
15
14
  for i = 1, #ready_jobs do
16
15
  local job_data = ready_jobs[i]
17
16
  local job = cjson.decode(job_data)
18
17
  local priority = job.priority or 5
19
- redis.call('ZADD', queue_key, priority, job_data)
18
+ local timestamp = tonumber(now)
19
+ local score = priority * 10000000000000 + timestamp
20
+ redis.call('ZADD', pending_key, score, job_data)
20
21
  redis.call('ZREM', delayed_key, job_data)
21
22
  end
23
+ end
24
+
25
+ -- Pop highest priority job (lowest score)
26
+ local result = redis.call('ZPOPMIN', pending_key)
27
+ if not result or #result == 0 then
28
+ return nil
29
+ end
30
+
31
+ local job_data = result[1]
32
+ local job = cjson.decode(job_data)
33
+
34
+ -- Store in active hash: jobId -> {workerId, acquiredAt, data}
35
+ local active_data = cjson.encode({
36
+ workerId = worker_id,
37
+ acquiredAt = tonumber(now),
38
+ data = job
39
+ })
40
+ redis.call('HSET', active_key, job.id, active_data)
41
+
42
+ -- Return job with acquiredAt
43
+ job.acquiredAt = tonumber(now)
44
+ return cjson.encode(job)
45
+ `;
46
+ var COMPLETE_JOB_SCRIPT = `
47
+ local active_key = KEYS[1]
48
+ local job_id = ARGV[1]
49
+
50
+ redis.call('HDEL', active_key, job_id)
51
+ return 1
52
+ `;
53
+ var FAIL_JOB_SCRIPT = `
54
+ local active_key = KEYS[1]
55
+ local job_id = ARGV[1]
56
+
57
+ redis.call('HDEL', active_key, job_id)
58
+ return 1
59
+ `;
60
+ var RETRY_JOB_SCRIPT = `
61
+ local active_key = KEYS[1]
62
+ local pending_key = KEYS[2]
63
+ local delayed_key = KEYS[3]
64
+ local job_id = ARGV[1]
65
+ local retry_at = tonumber(ARGV[2])
66
+ local now = tonumber(ARGV[3])
22
67
 
23
- return #ready_jobs
68
+ -- Get job from active hash
69
+ local active_data = redis.call('HGET', active_key, job_id)
70
+ if not active_data then
71
+ return 0
24
72
  end
25
73
 
26
- return 0
74
+ local active = cjson.decode(active_data)
75
+ local job = active.data
76
+
77
+ -- Remove from active
78
+ redis.call('HDEL', active_key, job_id)
79
+
80
+ -- Increment attempts
81
+ job.attempts = (job.attempts or 0) + 1
82
+
83
+ local job_data = cjson.encode(job)
84
+
85
+ -- Add back to pending or delayed
86
+ if retry_at and retry_at > now then
87
+ redis.call('ZADD', delayed_key, retry_at, job_data)
88
+ else
89
+ local priority = job.priority or 5
90
+ local score = priority * 10000000000000 + now
91
+ redis.call('ZADD', pending_key, score, job_data)
92
+ end
93
+
94
+ return 1
27
95
  `;
28
96
  function redis(config) {
29
97
  return () => {
30
98
  if (config instanceof Redis) {
31
- return new RedisAdapter(config);
99
+ return new RedisAdapter(config, false);
32
100
  }
33
101
  const options = {
34
102
  host: "localhost",
@@ -38,30 +106,95 @@ function redis(config) {
38
106
  ...config
39
107
  };
40
108
  const connection = new Redis(options);
41
- return new RedisAdapter(connection);
109
+ return new RedisAdapter(connection, true);
42
110
  };
43
111
  }
44
112
  var RedisAdapter = class {
45
113
  #connection;
46
- constructor(connection) {
114
+ #ownsConnection;
115
+ #workerId = "";
116
+ constructor(connection, ownsConnection = false) {
47
117
  this.#connection = connection;
118
+ this.#ownsConnection = ownsConnection;
48
119
  }
49
- createLeaseManager(config) {
50
- return new VerrouLeaseManager(config, this.#connection);
120
+ setWorkerId(workerId) {
121
+ this.#workerId = workerId;
51
122
  }
52
123
  async destroy() {
53
- await this.#connection.quit();
124
+ if (this.#ownsConnection) {
125
+ await this.#connection.quit();
126
+ }
54
127
  }
55
128
  pop() {
56
129
  return this.popFrom("default");
57
130
  }
58
131
  async popFrom(queue) {
59
- await this.#processDelayedJobs(queue);
60
- const queueContent = await this.#connection.zpopmin(`${redisKey}::${queue}`);
61
- if (queueContent && queueContent.length > 0) {
62
- return JSON.parse(queueContent[0]);
132
+ const now = Date.now();
133
+ const pendingKey = `${redisKey}::${queue}`;
134
+ const activeKey = `${redisKey}::${queue}::active`;
135
+ const delayedKey = `${redisKey}::delayed::${queue}`;
136
+ const result = await this.#connection.eval(
137
+ ACQUIRE_JOB_SCRIPT,
138
+ 3,
139
+ pendingKey,
140
+ activeKey,
141
+ delayedKey,
142
+ this.#workerId,
143
+ now.toString()
144
+ );
145
+ if (!result) {
146
+ return null;
63
147
  }
64
- return null;
148
+ return JSON.parse(result);
149
+ }
150
+ async popAndWait(queue, timeout) {
151
+ const immediate = await this.popFrom(queue);
152
+ if (immediate) {
153
+ return immediate;
154
+ }
155
+ const pendingKey = `${redisKey}::${queue}`;
156
+ const activeKey = `${redisKey}::${queue}::active`;
157
+ const now = Date.now();
158
+ const result = await this.#connection.bzpopmin(pendingKey, timeout / 1e3);
159
+ if (!result) {
160
+ return null;
161
+ }
162
+ const [, jobData] = result;
163
+ const job = JSON.parse(jobData);
164
+ const activeData = JSON.stringify({
165
+ workerId: this.#workerId,
166
+ acquiredAt: now,
167
+ data: job
168
+ });
169
+ await this.#connection.hset(activeKey, job.id, activeData);
170
+ return {
171
+ ...job,
172
+ acquiredAt: now
173
+ };
174
+ }
175
+ async completeJob(jobId, queue) {
176
+ const activeKey = `${redisKey}::${queue}::active`;
177
+ await this.#connection.eval(COMPLETE_JOB_SCRIPT, 1, activeKey, jobId);
178
+ }
179
+ async failJob(jobId, queue, _error) {
180
+ const activeKey = `${redisKey}::${queue}::active`;
181
+ await this.#connection.eval(FAIL_JOB_SCRIPT, 1, activeKey, jobId);
182
+ }
183
+ async retryJob(jobId, queue, retryAt) {
184
+ const now = Date.now();
185
+ const activeKey = `${redisKey}::${queue}::active`;
186
+ const pendingKey = `${redisKey}::${queue}`;
187
+ const delayedKey = `${redisKey}::delayed::${queue}`;
188
+ await this.#connection.eval(
189
+ RETRY_JOB_SCRIPT,
190
+ 3,
191
+ activeKey,
192
+ pendingKey,
193
+ delayedKey,
194
+ jobId,
195
+ retryAt ? retryAt.getTime().toString() : "0",
196
+ now.toString()
197
+ );
65
198
  }
66
199
  push(jobData) {
67
200
  return this.pushOn("default", jobData);
@@ -86,19 +219,6 @@ var RedisAdapter = class {
86
219
  sizeOf(queue) {
87
220
  return this.#connection.zcard(`${redisKey}::${queue}`);
88
221
  }
89
- async #processDelayedJobs(queue) {
90
- const now = Date.now();
91
- const delayedKey = `${redisKey}::delayed::${queue}`;
92
- const queueKey = `${redisKey}::${queue}`;
93
- return await this.#connection.eval(
94
- PROCESS_DELAYED_JOBS_SCRIPT,
95
- 2,
96
- // number of keys
97
- delayedKey,
98
- queueKey,
99
- now.toString()
100
- );
101
- }
102
222
  };
103
223
  export {
104
224
  RedisAdapter,
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/drivers/redis_adapter.ts"],"sourcesContent":["import { VerrouLeaseManager } from '#lease_managers/verrou'\nimport { Redis, type RedisOptions } from 'ioredis'\nimport type { Adapter } from '#contracts/adapter'\nimport type { JobData, LeaseConfig } from '#types/main'\nimport type { LeaseManager } from '#contracts/lease_manager'\n\nconst redisKey = 'jobs'\ntype RedisConfig = Redis | RedisOptions\n\n// Lua script for atomic delayed job processing\nconst PROCESS_DELAYED_JOBS_SCRIPT = `\n local delayed_key = KEYS[1]\n local queue_key = KEYS[2]\n local now = ARGV[1]\n\n -- Get ready jobs (score <= now)\n local ready_jobs = redis.call('ZRANGEBYSCORE', delayed_key, 0, now)\n\n if #ready_jobs > 0 then\n -- Move jobs to priority queue and remove from delayed queue atomically\n for i = 1, #ready_jobs do\n local job_data = ready_jobs[i]\n local job = cjson.decode(job_data)\n local priority = job.priority or 5\n redis.call('ZADD', queue_key, priority, job_data)\n redis.call('ZREM', delayed_key, job_data)\n end\n\n return #ready_jobs\n end\n\n return 0\n`\n\nexport function redis(config?: RedisConfig) {\n return () => {\n if (config instanceof Redis) {\n return new RedisAdapter(config)\n }\n\n // Create new Redis instance from options\n const options: RedisOptions = {\n host: 'localhost',\n port: 6379,\n keyPrefix: 'boringnode::queue::',\n db: 0,\n ...config,\n }\n\n const connection = new Redis(options)\n return new RedisAdapter(connection)\n }\n}\n\nexport class RedisAdapter implements Adapter {\n readonly #connection: Redis\n\n constructor(connection: Redis) {\n this.#connection = connection\n }\n\n createLeaseManager(config: LeaseConfig): LeaseManager {\n return new VerrouLeaseManager(config, this.#connection)\n }\n\n async destroy(): Promise<void> {\n await this.#connection.quit()\n }\n\n pop(): Promise<JobData | null> {\n return this.popFrom('default')\n }\n\n async popFrom(queue: string): Promise<JobData | null> {\n // First, move any ready delayed jobs to the regular queue\n await this.#processDelayedJobs(queue)\n\n // Pop from priority queue (sorted set) - highest priority (lowest score) first\n const queueContent = await this.#connection.zpopmin(`${redisKey}::${queue}`)\n\n if (queueContent && queueContent.length > 0) {\n return JSON.parse(queueContent[0])\n }\n\n return null\n }\n\n push(jobData: JobData): Promise<void> {\n return this.pushOn('default', jobData)\n }\n\n pushLater(jobData: JobData, delay: number): Promise<void> {\n return this.pushLaterOn('default', jobData, delay)\n }\n\n async pushLaterOn(queue: string, jobData: JobData, delay: number): Promise<void> {\n const executeAt = Date.now() + delay\n const delayedKey = `${redisKey}::delayed::${queue}`\n\n await this.#connection.zadd(delayedKey, executeAt, JSON.stringify(jobData))\n }\n\n async pushOn(queue: string, jobData: JobData): Promise<void> {\n const priority = jobData.priority ?? 5\n\n // Use priority as primary score, add timestamp for FIFO order within same priority\n // Date.now() precision is sufficient but perfect FIFO within the same millisecond is not guaranteed\n const timestamp = Date.now()\n const score = priority * 1e13 + timestamp\n\n await this.#connection.zadd(`${redisKey}::${queue}`, score, JSON.stringify(jobData))\n }\n\n size(): Promise<number> {\n return this.sizeOf('default')\n }\n\n sizeOf(queue: string): Promise<number> {\n return this.#connection.zcard(`${redisKey}::${queue}`)\n }\n\n async #processDelayedJobs(queue: string): Promise<number> {\n const now = Date.now()\n const delayedKey = `${redisKey}::delayed::${queue}`\n const queueKey = `${redisKey}::${queue}`\n\n // Use Lua script for atomic operation - much faster than pipeline\n return (await this.#connection.eval(\n PROCESS_DELAYED_JOBS_SCRIPT,\n 2, // number of keys\n delayedKey,\n queueKey,\n now.toString()\n )) as number\n }\n}\n"],"mappings":";AAAA,SAAS,0BAA0B;AACnC,SAAS,aAAgC;AAKzC,IAAM,WAAW;AAIjB,IAAM,8BAA8B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAwB7B,SAAS,MAAM,QAAsB;AAC1C,SAAO,MAAM;AACX,QAAI,kBAAkB,OAAO;AAC3B,aAAO,IAAI,aAAa,MAAM;AAAA,IAChC;AAGA,UAAM,UAAwB;AAAA,MAC5B,MAAM;AAAA,MACN,MAAM;AAAA,MACN,WAAW;AAAA,MACX,IAAI;AAAA,MACJ,GAAG;AAAA,IACL;AAEA,UAAM,aAAa,IAAI,MAAM,OAAO;AACpC,WAAO,IAAI,aAAa,UAAU;AAAA,EACpC;AACF;AAEO,IAAM,eAAN,MAAsC;AAAA,EAClC;AAAA,EAET,YAAY,YAAmB;AAC7B,SAAK,cAAc;AAAA,EACrB;AAAA,EAEA,mBAAmB,QAAmC;AACpD,WAAO,IAAI,mBAAmB,QAAQ,KAAK,WAAW;AAAA,EACxD;AAAA,EAEA,MAAM,UAAyB;AAC7B,UAAM,KAAK,YAAY,KAAK;AAAA,EAC9B;AAAA,EAEA,MAA+B;AAC7B,WAAO,KAAK,QAAQ,SAAS;AAAA,EAC/B;AAAA,EAEA,MAAM,QAAQ,OAAwC;AAEpD,UAAM,KAAK,oBAAoB,KAAK;AAGpC,UAAM,eAAe,MAAM,KAAK,YAAY,QAAQ,GAAG,QAAQ,KAAK,KAAK,EAAE;AAE3E,QAAI,gBAAgB,aAAa,SAAS,GAAG;AAC3C,aAAO,KAAK,MAAM,aAAa,CAAC,CAAC;AAAA,IACnC;AAEA,WAAO;AAAA,EACT;AAAA,EAEA,KAAK,SAAiC;AACpC,WAAO,KAAK,OAAO,WAAW,OAAO;AAAA,EACvC;AAAA,EAEA,UAAU,SAAkB,OAA8B;AACxD,WAAO,KAAK,YAAY,WAAW,SAAS,KAAK;AAAA,EACnD;AAAA,EAEA,MAAM,YAAY,OAAe,SAAkB,OAA8B;AAC/E,UAAM,YAAY,KAAK,IAAI,IAAI;AAC/B,UAAM,aAAa,GAAG,QAAQ,cAAc,KAAK;AAEjD,UAAM,KAAK,YAAY,KAAK,YAAY,WAAW,KAAK,UAAU,OAAO,CAAC;AAAA,EAC5E;AAAA,EAEA,MAAM,OAAO,OAAe,SAAiC;AAC3D,UAAM,WAAW,QAAQ,YAAY;AAIrC,UAAM,YAAY,KAAK,IAAI;AAC3B,UAAM,QAAQ,WAAW,OAAO;AAEhC,UAAM,KAAK,YAAY,KAAK,GAAG,QAAQ,KAAK,KAAK,IAAI,OAAO,KAAK,UAAU,OAAO,CAAC;AAAA,EACrF;AAAA,EAEA,OAAwB;AACtB,WAAO,KAAK,OAAO,SAAS;AAAA,EAC9B;AAAA,EAEA,OAAO,OAAgC;AACrC,WAAO,KAAK,YAAY,MAAM,GAAG,QAAQ,KAAK,KAAK,EAAE;AAAA,EACvD;AAAA,EAEA,MAAM,oBAAoB,OAAgC;AACxD,UAAM,MAAM,KAAK,IAAI;AACrB,UAAM,aAAa,GAAG,QAAQ,cAAc,KAAK;AACjD,UAAM,WAAW,GAAG,QAAQ,KAAK,KAAK;AAGtC,WAAQ,MAAM,KAAK,YAAY;AAAA,MAC7B;AAAA,MACA;AAAA;AAAA,MACA;AAAA,MACA;AAAA,MACA,IAAI,SAAS;AAAA,IACf;AAAA,EACF;AACF;","names":[]}
1
+ {"version":3,"sources":["../../../src/drivers/redis_adapter.ts"],"sourcesContent":["import { Redis, type RedisOptions } from 'ioredis'\nimport type { Adapter, AcquiredJob } from '#contracts/adapter'\nimport type { JobData } from '#types/main'\n\nconst redisKey = 'jobs'\ntype RedisConfig = Redis | RedisOptions\n\n/**\n * Lua script for atomic job acquisition.\n * 1. Check and process delayed jobs\n * 2. Pop from pending queue\n * 3. Add to active hash with worker info\n * 4. Return job data\n */\nconst ACQUIRE_JOB_SCRIPT = `\n local pending_key = KEYS[1]\n local active_key = KEYS[2]\n local delayed_key = KEYS[3]\n local worker_id = ARGV[1]\n local now = ARGV[2]\n\n -- First, process delayed jobs\n local ready_jobs = redis.call('ZRANGEBYSCORE', delayed_key, 0, now)\n if #ready_jobs > 0 then\n for i = 1, #ready_jobs do\n local job_data = ready_jobs[i]\n local job = cjson.decode(job_data)\n local priority = job.priority or 5\n local timestamp = tonumber(now)\n local score = priority * 10000000000000 + timestamp\n redis.call('ZADD', pending_key, score, job_data)\n redis.call('ZREM', delayed_key, job_data)\n end\n end\n\n -- Pop highest priority job (lowest score)\n local result = redis.call('ZPOPMIN', pending_key)\n if not result or #result == 0 then\n return nil\n end\n\n local job_data = result[1]\n local job = cjson.decode(job_data)\n\n -- Store in active hash: jobId -> {workerId, acquiredAt, data}\n local active_data = cjson.encode({\n workerId = worker_id,\n acquiredAt = tonumber(now),\n data = job\n })\n redis.call('HSET', active_key, job.id, active_data)\n\n -- Return job with acquiredAt\n job.acquiredAt = tonumber(now)\n return cjson.encode(job)\n`\n\n/**\n * Lua script for completing a job.\n * Removes the job from active hash.\n */\nconst COMPLETE_JOB_SCRIPT = `\n local active_key = KEYS[1]\n local job_id = ARGV[1]\n\n redis.call('HDEL', active_key, job_id)\n return 1\n`\n\n/**\n * Lua script for failing a job permanently.\n * Removes from active hash.\n */\nconst FAIL_JOB_SCRIPT = `\n local active_key = KEYS[1]\n local job_id = ARGV[1]\n\n redis.call('HDEL', active_key, job_id)\n return 1\n`\n\n/**\n * Lua script for retrying a job.\n * 1. Get job from active hash\n * 2. Remove from active hash\n * 3. Increment attempts\n * 4. Add back to pending (or delayed if retryAt is set)\n */\nconst RETRY_JOB_SCRIPT = `\n local active_key = KEYS[1]\n local pending_key = KEYS[2]\n local delayed_key = KEYS[3]\n local job_id = ARGV[1]\n local retry_at = tonumber(ARGV[2])\n local now = tonumber(ARGV[3])\n\n -- Get job from active hash\n local active_data = redis.call('HGET', active_key, job_id)\n if not active_data then\n return 0\n end\n\n local active = cjson.decode(active_data)\n local job = active.data\n\n -- Remove from active\n redis.call('HDEL', active_key, job_id)\n\n -- Increment attempts\n job.attempts = (job.attempts or 0) + 1\n\n local job_data = cjson.encode(job)\n\n -- Add back to pending or delayed\n if retry_at and retry_at > now then\n redis.call('ZADD', delayed_key, retry_at, job_data)\n else\n local priority = job.priority or 5\n local score = priority * 10000000000000 + now\n redis.call('ZADD', pending_key, score, job_data)\n end\n\n return 1\n`\n\n/**\n * Create a new Redis adapter factory.\n * Accepts either a Redis instance or Redis options.\n *\n * When passing options, the adapter will create and manage\n * the connection lifecycle (closing it on destroy).\n *\n * When passing a Redis instance, the caller is responsible for\n * managing the connection lifecycle.\n */\nexport function redis(config?: RedisConfig) {\n return () => {\n if (config instanceof Redis) {\n return new RedisAdapter(config, false)\n }\n\n const options: RedisOptions = {\n host: 'localhost',\n port: 6379,\n keyPrefix: 'boringnode::queue::',\n db: 0,\n ...config,\n }\n\n const connection = new Redis(options)\n return new RedisAdapter(connection, true)\n }\n}\n\nexport class RedisAdapter implements Adapter {\n readonly #connection: Redis\n readonly #ownsConnection: boolean\n #workerId: string = ''\n\n constructor(connection: Redis, ownsConnection: boolean = false) {\n this.#connection = connection\n this.#ownsConnection = ownsConnection\n }\n\n setWorkerId(workerId: string): void {\n this.#workerId = workerId\n }\n\n async destroy(): Promise<void> {\n if (this.#ownsConnection) {\n await this.#connection.quit()\n }\n }\n\n pop(): Promise<AcquiredJob | null> {\n return this.popFrom('default')\n }\n\n async popFrom(queue: string): Promise<AcquiredJob | null> {\n const now = Date.now()\n const pendingKey = `${redisKey}::${queue}`\n const activeKey = `${redisKey}::${queue}::active`\n const delayedKey = `${redisKey}::delayed::${queue}`\n\n const result = await this.#connection.eval(\n ACQUIRE_JOB_SCRIPT,\n 3,\n pendingKey,\n activeKey,\n delayedKey,\n this.#workerId,\n now.toString()\n )\n\n if (!result) {\n return null\n }\n\n return JSON.parse(result as string)\n }\n\n async popAndWait(queue: string, timeout: number): Promise<AcquiredJob | null> {\n // First try immediate pop\n const immediate = await this.popFrom(queue)\n if (immediate) {\n return immediate\n }\n\n // Wait for new job using BZPOPMIN on pending queue\n const pendingKey = `${redisKey}::${queue}`\n const activeKey = `${redisKey}::${queue}::active`\n const now = Date.now()\n\n // BZPOPMIN returns [key, member, score] or null\n const result = await this.#connection.bzpopmin(pendingKey, timeout / 1000)\n\n if (!result) {\n return null\n }\n\n const [, jobData] = result\n const job = JSON.parse(jobData)\n\n // Store in active hash\n const activeData = JSON.stringify({\n workerId: this.#workerId,\n acquiredAt: now,\n data: job,\n })\n await this.#connection.hset(activeKey, job.id, activeData)\n\n return {\n ...job,\n acquiredAt: now,\n }\n }\n\n async completeJob(jobId: string, queue: string): Promise<void> {\n const activeKey = `${redisKey}::${queue}::active`\n\n await this.#connection.eval(COMPLETE_JOB_SCRIPT, 1, activeKey, jobId)\n }\n\n async failJob(jobId: string, queue: string, _error?: Error): Promise<void> {\n const activeKey = `${redisKey}::${queue}::active`\n\n await this.#connection.eval(FAIL_JOB_SCRIPT, 1, activeKey, jobId)\n }\n\n async retryJob(jobId: string, queue: string, retryAt?: Date): Promise<void> {\n const now = Date.now()\n const activeKey = `${redisKey}::${queue}::active`\n const pendingKey = `${redisKey}::${queue}`\n const delayedKey = `${redisKey}::delayed::${queue}`\n\n await this.#connection.eval(\n RETRY_JOB_SCRIPT,\n 3,\n activeKey,\n pendingKey,\n delayedKey,\n jobId,\n retryAt ? retryAt.getTime().toString() : '0',\n now.toString()\n )\n }\n\n push(jobData: JobData): Promise<void> {\n return this.pushOn('default', jobData)\n }\n\n pushLater(jobData: JobData, delay: number): Promise<void> {\n return this.pushLaterOn('default', jobData, delay)\n }\n\n async pushLaterOn(queue: string, jobData: JobData, delay: number): Promise<void> {\n const executeAt = Date.now() + delay\n const delayedKey = `${redisKey}::delayed::${queue}`\n\n await this.#connection.zadd(delayedKey, executeAt, JSON.stringify(jobData))\n }\n\n async pushOn(queue: string, jobData: JobData): Promise<void> {\n const priority = jobData.priority ?? 5\n\n // Use priority as primary score, add timestamp for FIFO order within same priority\n // Date.now() precision is sufficient but perfect FIFO within the same millisecond is not guaranteed\n const timestamp = Date.now()\n const score = priority * 1e13 + timestamp\n\n await this.#connection.zadd(`${redisKey}::${queue}`, score, JSON.stringify(jobData))\n }\n\n size(): Promise<number> {\n return this.sizeOf('default')\n }\n\n sizeOf(queue: string): Promise<number> {\n return this.#connection.zcard(`${redisKey}::${queue}`)\n }\n}\n"],"mappings":"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","names":[]}
@@ -1,18 +1,24 @@
1
- import { A as Adapter, L as LeaseConfig, a as JobData } from '../../job-CcAUWe8j.js';
2
- import { LeaseManager } from '../contracts/lease_manager.js';
1
+ import { A as Adapter, b as JobData, a as AcquiredJob } from '../../job-Bd_c2lFK.js';
3
2
 
4
3
  declare function sync(): () => SyncAdapter;
4
+ /**
5
+ * Sync adapter executes jobs immediately when pushed.
6
+ * Pop/complete/fail/retry are not supported as jobs are executed synchronously.
7
+ */
5
8
  declare class SyncAdapter implements Adapter {
6
9
  #private;
7
- createLeaseManager(_config: LeaseConfig): LeaseManager;
10
+ setWorkerId(_workerId: string): void;
8
11
  push(jobData: JobData): Promise<void>;
9
12
  pushOn(_queue: string, jobData: JobData): Promise<void>;
10
13
  pushLater(jobData: JobData, delay: number): Promise<void>;
11
14
  pushLaterOn(_queue: string, jobData: JobData, delay: number): Promise<void>;
12
15
  size(): Promise<number>;
13
16
  sizeOf(_queue: string): Promise<number>;
14
- pop(): Promise<JobData | null>;
15
- popFrom(_queue: string): Promise<JobData | null>;
17
+ pop(): Promise<AcquiredJob | null>;
18
+ popFrom(_queue: string): Promise<AcquiredJob | null>;
19
+ completeJob(_jobId: string, _queue: string): Promise<void>;
20
+ failJob(_jobId: string, _queue: string, _error?: Error): Promise<void>;
21
+ retryJob(_jobId: string, _queue: string, _retryAt?: Date): Promise<void>;
16
22
  destroy(): Promise<void>;
17
23
  }
18
24
 
@@ -4,8 +4,7 @@ function sync() {
4
4
  return () => new SyncAdapter();
5
5
  }
6
6
  var SyncAdapter = class {
7
- createLeaseManager(_config) {
8
- throw new Error("Method not implemented.");
7
+ setWorkerId(_workerId) {
9
8
  }
10
9
  push(jobData) {
11
10
  return this.pushOn("default", jobData);
@@ -32,7 +31,16 @@ var SyncAdapter = class {
32
31
  return this.popFrom("default");
33
32
  }
34
33
  popFrom(_queue) {
35
- throw new Error("Method not implemented.");
34
+ throw new Error("SyncAdapter does not support pop - jobs are executed immediately on push");
35
+ }
36
+ completeJob(_jobId, _queue) {
37
+ return Promise.resolve();
38
+ }
39
+ failJob(_jobId, _queue, _error) {
40
+ return Promise.resolve();
41
+ }
42
+ retryJob(_jobId, _queue, _retryAt) {
43
+ return Promise.resolve();
36
44
  }
37
45
  destroy() {
38
46
  return Promise.resolve();
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/drivers/sync_adapter.ts"],"sourcesContent":["import { Locator } from '#src/locator'\nimport type { Adapter } from '#contracts/adapter'\nimport type { JobData, LeaseConfig } from '#types/main'\nimport type { LeaseManager } from '#contracts/lease_manager'\n\nexport function sync() {\n return () => new SyncAdapter()\n}\n\nexport class SyncAdapter implements Adapter {\n createLeaseManager(_config: LeaseConfig): LeaseManager {\n throw new Error('Method not implemented.')\n }\n\n push(jobData: JobData): Promise<void> {\n return this.pushOn('default', jobData)\n }\n\n pushOn(_queue: string, jobData: JobData): Promise<void> {\n return this.#execute(jobData.name, jobData.payload)\n }\n\n pushLater(jobData: JobData, delay: number): Promise<void> {\n return this.pushLaterOn('default', jobData, delay)\n }\n\n pushLaterOn(_queue: string, jobData: JobData, delay: number): Promise<void> {\n setTimeout(() => {\n void this.#execute(jobData.name, jobData.payload)\n }, delay)\n\n return Promise.resolve()\n }\n\n size(): Promise<number> {\n return this.sizeOf('default')\n }\n\n sizeOf(_queue: string): Promise<number> {\n return Promise.resolve(0)\n }\n\n pop(): Promise<JobData | null> {\n return this.popFrom('default')\n }\n\n popFrom(_queue: string): Promise<JobData | null> {\n throw new Error('Method not implemented.')\n }\n\n destroy(): Promise<void> {\n return Promise.resolve()\n }\n\n async #execute(jobName: string, payload: any): Promise<any> {\n const JobClass = Locator.get(jobName)\n\n if (!JobClass) {\n throw new Error(`Job class ${jobName} not found.`)\n }\n\n const jobInstance = new JobClass(payload)\n await jobInstance.execute()\n }\n}\n"],"mappings":";AAAA,SAAS,eAAe;AAKjB,SAAS,OAAO;AACrB,SAAO,MAAM,IAAI,YAAY;AAC/B;AAEO,IAAM,cAAN,MAAqC;AAAA,EAC1C,mBAAmB,SAAoC;AACrD,UAAM,IAAI,MAAM,yBAAyB;AAAA,EAC3C;AAAA,EAEA,KAAK,SAAiC;AACpC,WAAO,KAAK,OAAO,WAAW,OAAO;AAAA,EACvC;AAAA,EAEA,OAAO,QAAgB,SAAiC;AACtD,WAAO,KAAK,SAAS,QAAQ,MAAM,QAAQ,OAAO;AAAA,EACpD;AAAA,EAEA,UAAU,SAAkB,OAA8B;AACxD,WAAO,KAAK,YAAY,WAAW,SAAS,KAAK;AAAA,EACnD;AAAA,EAEA,YAAY,QAAgB,SAAkB,OAA8B;AAC1E,eAAW,MAAM;AACf,WAAK,KAAK,SAAS,QAAQ,MAAM,QAAQ,OAAO;AAAA,IAClD,GAAG,KAAK;AAER,WAAO,QAAQ,QAAQ;AAAA,EACzB;AAAA,EAEA,OAAwB;AACtB,WAAO,KAAK,OAAO,SAAS;AAAA,EAC9B;AAAA,EAEA,OAAO,QAAiC;AACtC,WAAO,QAAQ,QAAQ,CAAC;AAAA,EAC1B;AAAA,EAEA,MAA+B;AAC7B,WAAO,KAAK,QAAQ,SAAS;AAAA,EAC/B;AAAA,EAEA,QAAQ,QAAyC;AAC/C,UAAM,IAAI,MAAM,yBAAyB;AAAA,EAC3C;AAAA,EAEA,UAAyB;AACvB,WAAO,QAAQ,QAAQ;AAAA,EACzB;AAAA,EAEA,MAAM,SAAS,SAAiB,SAA4B;AAC1D,UAAM,WAAW,QAAQ,IAAI,OAAO;AAEpC,QAAI,CAAC,UAAU;AACb,YAAM,IAAI,MAAM,aAAa,OAAO,aAAa;AAAA,IACnD;AAEA,UAAM,cAAc,IAAI,SAAS,OAAO;AACxC,UAAM,YAAY,QAAQ;AAAA,EAC5B;AACF;","names":[]}
1
+ {"version":3,"sources":["../../../src/drivers/sync_adapter.ts"],"sourcesContent":["import { Locator } from '#src/locator'\nimport type { Adapter, AcquiredJob } from '#contracts/adapter'\nimport type { JobData } from '#types/main'\n\nexport function sync() {\n return () => new SyncAdapter()\n}\n\n/**\n * Sync adapter executes jobs immediately when pushed.\n * Pop/complete/fail/retry are not supported as jobs are executed synchronously.\n */\nexport class SyncAdapter implements Adapter {\n setWorkerId(_workerId: string): void {}\n\n push(jobData: JobData): Promise<void> {\n return this.pushOn('default', jobData)\n }\n\n pushOn(_queue: string, jobData: JobData): Promise<void> {\n return this.#execute(jobData.name, jobData.payload)\n }\n\n pushLater(jobData: JobData, delay: number): Promise<void> {\n return this.pushLaterOn('default', jobData, delay)\n }\n\n pushLaterOn(_queue: string, jobData: JobData, delay: number): Promise<void> {\n setTimeout(() => {\n void this.#execute(jobData.name, jobData.payload)\n }, delay)\n\n return Promise.resolve()\n }\n\n size(): Promise<number> {\n return this.sizeOf('default')\n }\n\n sizeOf(_queue: string): Promise<number> {\n return Promise.resolve(0)\n }\n\n pop(): Promise<AcquiredJob | null> {\n return this.popFrom('default')\n }\n\n popFrom(_queue: string): Promise<AcquiredJob | null> {\n throw new Error('SyncAdapter does not support pop - jobs are executed immediately on push')\n }\n\n completeJob(_jobId: string, _queue: string): Promise<void> {\n return Promise.resolve()\n }\n\n failJob(_jobId: string, _queue: string, _error?: Error): Promise<void> {\n return Promise.resolve()\n }\n\n retryJob(_jobId: string, _queue: string, _retryAt?: Date): Promise<void> {\n return Promise.resolve()\n }\n\n destroy(): Promise<void> {\n return Promise.resolve()\n }\n\n async #execute(jobName: string, payload: any): Promise<any> {\n const JobClass = Locator.get(jobName)\n\n if (!JobClass) {\n throw new Error(`Job class ${jobName} not found.`)\n }\n\n const jobInstance = new JobClass(payload)\n await jobInstance.execute()\n }\n}\n"],"mappings":";AAAA,SAAS,eAAe;AAIjB,SAAS,OAAO;AACrB,SAAO,MAAM,IAAI,YAAY;AAC/B;AAMO,IAAM,cAAN,MAAqC;AAAA,EAC1C,YAAY,WAAyB;AAAA,EAAC;AAAA,EAEtC,KAAK,SAAiC;AACpC,WAAO,KAAK,OAAO,WAAW,OAAO;AAAA,EACvC;AAAA,EAEA,OAAO,QAAgB,SAAiC;AACtD,WAAO,KAAK,SAAS,QAAQ,MAAM,QAAQ,OAAO;AAAA,EACpD;AAAA,EAEA,UAAU,SAAkB,OAA8B;AACxD,WAAO,KAAK,YAAY,WAAW,SAAS,KAAK;AAAA,EACnD;AAAA,EAEA,YAAY,QAAgB,SAAkB,OAA8B;AAC1E,eAAW,MAAM;AACf,WAAK,KAAK,SAAS,QAAQ,MAAM,QAAQ,OAAO;AAAA,IAClD,GAAG,KAAK;AAER,WAAO,QAAQ,QAAQ;AAAA,EACzB;AAAA,EAEA,OAAwB;AACtB,WAAO,KAAK,OAAO,SAAS;AAAA,EAC9B;AAAA,EAEA,OAAO,QAAiC;AACtC,WAAO,QAAQ,QAAQ,CAAC;AAAA,EAC1B;AAAA,EAEA,MAAmC;AACjC,WAAO,KAAK,QAAQ,SAAS;AAAA,EAC/B;AAAA,EAEA,QAAQ,QAA6C;AACnD,UAAM,IAAI,MAAM,0EAA0E;AAAA,EAC5F;AAAA,EAEA,YAAY,QAAgB,QAA+B;AACzD,WAAO,QAAQ,QAAQ;AAAA,EACzB;AAAA,EAEA,QAAQ,QAAgB,QAAgB,QAA+B;AACrE,WAAO,QAAQ,QAAQ;AAAA,EACzB;AAAA,EAEA,SAAS,QAAgB,QAAgB,UAAgC;AACvE,WAAO,QAAQ,QAAQ;AAAA,EACzB;AAAA,EAEA,UAAyB;AACvB,WAAO,QAAQ,QAAQ;AAAA,EACzB;AAAA,EAEA,MAAM,SAAS,SAAiB,SAA4B;AAC1D,UAAM,WAAW,QAAQ,IAAI,OAAO;AAEpC,QAAI,CAAC,UAAU;AACb,YAAM,IAAI,MAAM,aAAa,OAAO,aAAa;AAAA,IACnD;AAEA,UAAM,cAAc,IAAI,SAAS,OAAO;AACxC,UAAM,YAAY,QAAQ;AAAA,EAC5B;AACF;","names":[]}
@@ -1,2 +1 @@
1
- export { b as AcquiredJob, k as AdapterFactory, h as BackoffConfig, B as BackoffStrategy, D as Duration, g as JobClass, a as JobData, d as JobOptions, L as LeaseConfig, i as QueueConfig, Q as QueueManagerConfig, R as RetryConfig, j as WorkerConfig, W as WorkerCycle } from '../../job-CcAUWe8j.js';
2
- import '../contracts/lease_manager.js';
1
+ export { k as AdapterFactory, h as BackoffConfig, B as BackoffStrategy, D as Duration, g as JobClass, b as JobData, d as JobOptions, i as QueueConfig, Q as QueueManagerConfig, R as RetryConfig, j as WorkerConfig, W as WorkerCycle } from '../../job-Bd_c2lFK.js';
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@boringnode/queue",
3
3
  "description": "A simple and efficient queue system for Node.js applications",
4
- "version": "0.0.1-alpha",
4
+ "version": "0.0.1-alpha.1",
5
5
  "main": "build/index.js",
6
6
  "type": "module",
7
7
  "files": [
@@ -22,6 +22,9 @@
22
22
  "#types/*": "./src/types/*.ts"
23
23
  },
24
24
  "scripts": {
25
+ "benchmark": "node benchmark/run.ts",
26
+ "benchmark:quick": "node benchmark/run.ts --quick",
27
+ "benchmark:full": "node benchmark/run.ts --full",
25
28
  "build": "yarn clean && tsup-node",
26
29
  "clean": "del-cli build",
27
30
  "format": "prettier --write .",
@@ -33,8 +36,7 @@
33
36
  },
34
37
  "dependencies": {
35
38
  "@lukeed/ms": "^2.0.2",
36
- "@poppinss/utils": "^6.10.1",
37
- "@verrou/core": "^0.5.1"
39
+ "@poppinss/utils": "^6.10.1"
38
40
  },
39
41
  "devDependencies": {
40
42
  "@adonisjs/eslint-config": "^2.1.2",
@@ -44,11 +46,17 @@
44
46
  "@japa/expect-type": "^2.0.3",
45
47
  "@japa/file-system": "^2.3.2",
46
48
  "@japa/runner": "^4.4.0",
49
+ "@types/better-sqlite3": "^7.6.13",
47
50
  "@types/node": "^24.3.1",
51
+ "@types/pg": "^8",
52
+ "better-sqlite3": "^12.5.0",
53
+ "bullmq": "^5.65.1",
48
54
  "c8": "^10.1.3",
49
55
  "del-cli": "^7.0.0",
50
56
  "eslint": "^9.35.0",
51
57
  "ioredis": "^5.7.0",
58
+ "knex": "^3.1.0",
59
+ "pg": "^8.16.3",
52
60
  "prettier": "^3.6.2",
53
61
  "release-it": "^19.0.4",
54
62
  "testcontainers": "^11.5.1",
@@ -1,8 +0,0 @@
1
- interface LeaseManager {
2
- acquire(jobId: string): Promise<boolean>;
3
- renew(jobId: string): Promise<boolean>;
4
- release(jobId: string): Promise<void>;
5
- destroy(): Promise<void>;
6
- }
7
-
8
- export type { LeaseManager };
@@ -1 +0,0 @@
1
- //# sourceMappingURL=lease_manager.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}