bunqueue 1.0.0

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.
Files changed (215) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +640 -0
  3. package/dist/application/dlqManager.d.ts +19 -0
  4. package/dist/application/dlqManager.d.ts.map +1 -0
  5. package/dist/application/dlqManager.js +44 -0
  6. package/dist/application/dlqManager.js.map +1 -0
  7. package/dist/application/eventsManager.d.ts +28 -0
  8. package/dist/application/eventsManager.d.ts.map +1 -0
  9. package/dist/application/eventsManager.js +59 -0
  10. package/dist/application/eventsManager.js.map +1 -0
  11. package/dist/application/jobLogsManager.d.ts +20 -0
  12. package/dist/application/jobLogsManager.d.ts.map +1 -0
  13. package/dist/application/jobLogsManager.js +28 -0
  14. package/dist/application/jobLogsManager.js.map +1 -0
  15. package/dist/application/metricsExporter.d.ts +24 -0
  16. package/dist/application/metricsExporter.d.ts.map +1 -0
  17. package/dist/application/metricsExporter.js +80 -0
  18. package/dist/application/metricsExporter.js.map +1 -0
  19. package/dist/application/operations/ack.d.ts +48 -0
  20. package/dist/application/operations/ack.d.ts.map +1 -0
  21. package/dist/application/operations/ack.js +109 -0
  22. package/dist/application/operations/ack.js.map +1 -0
  23. package/dist/application/operations/index.d.ts +10 -0
  24. package/dist/application/operations/index.d.ts.map +1 -0
  25. package/dist/application/operations/index.js +10 -0
  26. package/dist/application/operations/index.js.map +1 -0
  27. package/dist/application/operations/jobManagement.d.ts +32 -0
  28. package/dist/application/operations/jobManagement.d.ts.map +1 -0
  29. package/dist/application/operations/jobManagement.js +122 -0
  30. package/dist/application/operations/jobManagement.js.map +1 -0
  31. package/dist/application/operations/pull.d.ts +36 -0
  32. package/dist/application/operations/pull.d.ts.map +1 -0
  33. package/dist/application/operations/pull.js +109 -0
  34. package/dist/application/operations/pull.js.map +1 -0
  35. package/dist/application/operations/push.d.ts +36 -0
  36. package/dist/application/operations/push.d.ts.map +1 -0
  37. package/dist/application/operations/push.js +94 -0
  38. package/dist/application/operations/push.js.map +1 -0
  39. package/dist/application/operations/queryOperations.d.ts +33 -0
  40. package/dist/application/operations/queryOperations.d.ts.map +1 -0
  41. package/dist/application/operations/queryOperations.js +57 -0
  42. package/dist/application/operations/queryOperations.js.map +1 -0
  43. package/dist/application/operations/queueControl.d.ts +32 -0
  44. package/dist/application/operations/queueControl.d.ts.map +1 -0
  45. package/dist/application/operations/queueControl.js +72 -0
  46. package/dist/application/operations/queueControl.js.map +1 -0
  47. package/dist/application/queueManager.d.ts +113 -0
  48. package/dist/application/queueManager.d.ts.map +1 -0
  49. package/dist/application/queueManager.js +406 -0
  50. package/dist/application/queueManager.js.map +1 -0
  51. package/dist/application/webhookManager.d.ts +35 -0
  52. package/dist/application/webhookManager.d.ts.map +1 -0
  53. package/dist/application/webhookManager.js +109 -0
  54. package/dist/application/webhookManager.js.map +1 -0
  55. package/dist/application/workerManager.d.ts +48 -0
  56. package/dist/application/workerManager.d.ts.map +1 -0
  57. package/dist/application/workerManager.js +121 -0
  58. package/dist/application/workerManager.js.map +1 -0
  59. package/dist/domain/queue/index.d.ts +6 -0
  60. package/dist/domain/queue/index.d.ts.map +1 -0
  61. package/dist/domain/queue/index.js +6 -0
  62. package/dist/domain/queue/index.js.map +1 -0
  63. package/dist/domain/queue/priorityQueue.d.ts +45 -0
  64. package/dist/domain/queue/priorityQueue.d.ts.map +1 -0
  65. package/dist/domain/queue/priorityQueue.js +203 -0
  66. package/dist/domain/queue/priorityQueue.js.map +1 -0
  67. package/dist/domain/queue/shard.d.ts +98 -0
  68. package/dist/domain/queue/shard.d.ts.map +1 -0
  69. package/dist/domain/queue/shard.js +245 -0
  70. package/dist/domain/queue/shard.js.map +1 -0
  71. package/dist/domain/types/command.d.ts +270 -0
  72. package/dist/domain/types/command.d.ts.map +1 -0
  73. package/dist/domain/types/command.js +6 -0
  74. package/dist/domain/types/command.js.map +1 -0
  75. package/dist/domain/types/cron.d.ts +32 -0
  76. package/dist/domain/types/cron.d.ts.map +1 -0
  77. package/dist/domain/types/cron.js +31 -0
  78. package/dist/domain/types/cron.js.map +1 -0
  79. package/dist/domain/types/index.d.ts +9 -0
  80. package/dist/domain/types/index.d.ts.map +1 -0
  81. package/dist/domain/types/index.js +9 -0
  82. package/dist/domain/types/index.js.map +1 -0
  83. package/dist/domain/types/job.d.ts +94 -0
  84. package/dist/domain/types/job.d.ts.map +1 -0
  85. package/dist/domain/types/job.js +81 -0
  86. package/dist/domain/types/job.js.map +1 -0
  87. package/dist/domain/types/queue.d.ts +86 -0
  88. package/dist/domain/types/queue.d.ts.map +1 -0
  89. package/dist/domain/types/queue.js +84 -0
  90. package/dist/domain/types/queue.js.map +1 -0
  91. package/dist/domain/types/response.d.ts +158 -0
  92. package/dist/domain/types/response.d.ts.map +1 -0
  93. package/dist/domain/types/response.js +86 -0
  94. package/dist/domain/types/response.js.map +1 -0
  95. package/dist/domain/types/webhook.d.ts +33 -0
  96. package/dist/domain/types/webhook.d.ts.map +1 -0
  97. package/dist/domain/types/webhook.js +20 -0
  98. package/dist/domain/types/webhook.js.map +1 -0
  99. package/dist/domain/types/worker.d.ts +27 -0
  100. package/dist/domain/types/worker.d.ts.map +1 -0
  101. package/dist/domain/types/worker.js +27 -0
  102. package/dist/domain/types/worker.js.map +1 -0
  103. package/dist/infrastructure/persistence/index.d.ts +6 -0
  104. package/dist/infrastructure/persistence/index.d.ts.map +1 -0
  105. package/dist/infrastructure/persistence/index.js +6 -0
  106. package/dist/infrastructure/persistence/index.js.map +1 -0
  107. package/dist/infrastructure/persistence/schema.d.ts +14 -0
  108. package/dist/infrastructure/persistence/schema.d.ts.map +1 -0
  109. package/dist/infrastructure/persistence/schema.js +123 -0
  110. package/dist/infrastructure/persistence/schema.js.map +1 -0
  111. package/dist/infrastructure/persistence/sqlite.d.ts +42 -0
  112. package/dist/infrastructure/persistence/sqlite.d.ts.map +1 -0
  113. package/dist/infrastructure/persistence/sqlite.js +164 -0
  114. package/dist/infrastructure/persistence/sqlite.js.map +1 -0
  115. package/dist/infrastructure/persistence/statements.d.ts +55 -0
  116. package/dist/infrastructure/persistence/statements.d.ts.map +1 -0
  117. package/dist/infrastructure/persistence/statements.js +42 -0
  118. package/dist/infrastructure/persistence/statements.js.map +1 -0
  119. package/dist/infrastructure/scheduler/cronParser.d.ts +44 -0
  120. package/dist/infrastructure/scheduler/cronParser.d.ts.map +1 -0
  121. package/dist/infrastructure/scheduler/cronParser.js +90 -0
  122. package/dist/infrastructure/scheduler/cronParser.js.map +1 -0
  123. package/dist/infrastructure/scheduler/cronScheduler.d.ts +68 -0
  124. package/dist/infrastructure/scheduler/cronScheduler.d.ts.map +1 -0
  125. package/dist/infrastructure/scheduler/cronScheduler.js +172 -0
  126. package/dist/infrastructure/scheduler/cronScheduler.js.map +1 -0
  127. package/dist/infrastructure/scheduler/index.d.ts +6 -0
  128. package/dist/infrastructure/scheduler/index.d.ts.map +1 -0
  129. package/dist/infrastructure/scheduler/index.js +6 -0
  130. package/dist/infrastructure/scheduler/index.js.map +1 -0
  131. package/dist/infrastructure/server/handler.d.ts +13 -0
  132. package/dist/infrastructure/server/handler.d.ts.map +1 -0
  133. package/dist/infrastructure/server/handler.js +167 -0
  134. package/dist/infrastructure/server/handler.js.map +1 -0
  135. package/dist/infrastructure/server/handlers/advanced.d.ts +68 -0
  136. package/dist/infrastructure/server/handlers/advanced.d.ts.map +1 -0
  137. package/dist/infrastructure/server/handlers/advanced.js +99 -0
  138. package/dist/infrastructure/server/handlers/advanced.js.map +1 -0
  139. package/dist/infrastructure/server/handlers/core.d.ts +36 -0
  140. package/dist/infrastructure/server/handlers/core.d.ts.map +1 -0
  141. package/dist/infrastructure/server/handlers/core.js +82 -0
  142. package/dist/infrastructure/server/handlers/core.js.map +1 -0
  143. package/dist/infrastructure/server/handlers/cron.d.ts +20 -0
  144. package/dist/infrastructure/server/handlers/cron.d.ts.map +1 -0
  145. package/dist/infrastructure/server/handlers/cron.js +56 -0
  146. package/dist/infrastructure/server/handlers/cron.js.map +1 -0
  147. package/dist/infrastructure/server/handlers/dlq.d.ts +20 -0
  148. package/dist/infrastructure/server/handlers/dlq.d.ts.map +1 -0
  149. package/dist/infrastructure/server/handlers/dlq.js +31 -0
  150. package/dist/infrastructure/server/handlers/dlq.js.map +1 -0
  151. package/dist/infrastructure/server/handlers/index.d.ts +7 -0
  152. package/dist/infrastructure/server/handlers/index.d.ts.map +1 -0
  153. package/dist/infrastructure/server/handlers/index.js +7 -0
  154. package/dist/infrastructure/server/handlers/index.js.map +1 -0
  155. package/dist/infrastructure/server/handlers/management.d.ts +36 -0
  156. package/dist/infrastructure/server/handlers/management.d.ts.map +1 -0
  157. package/dist/infrastructure/server/handlers/management.js +75 -0
  158. package/dist/infrastructure/server/handlers/management.js.map +1 -0
  159. package/dist/infrastructure/server/handlers/monitoring.d.ts +18 -0
  160. package/dist/infrastructure/server/handlers/monitoring.d.ts.map +1 -0
  161. package/dist/infrastructure/server/handlers/monitoring.js +102 -0
  162. package/dist/infrastructure/server/handlers/monitoring.js.map +1 -0
  163. package/dist/infrastructure/server/handlers/query.d.ts +32 -0
  164. package/dist/infrastructure/server/handlers/query.d.ts.map +1 -0
  165. package/dist/infrastructure/server/handlers/query.js +61 -0
  166. package/dist/infrastructure/server/handlers/query.js.map +1 -0
  167. package/dist/infrastructure/server/http.d.ts +43 -0
  168. package/dist/infrastructure/server/http.d.ts.map +1 -0
  169. package/dist/infrastructure/server/http.js +344 -0
  170. package/dist/infrastructure/server/http.js.map +1 -0
  171. package/dist/infrastructure/server/index.d.ts +8 -0
  172. package/dist/infrastructure/server/index.d.ts.map +1 -0
  173. package/dist/infrastructure/server/index.js +8 -0
  174. package/dist/infrastructure/server/index.js.map +1 -0
  175. package/dist/infrastructure/server/protocol.d.ts +44 -0
  176. package/dist/infrastructure/server/protocol.d.ts.map +1 -0
  177. package/dist/infrastructure/server/protocol.js +129 -0
  178. package/dist/infrastructure/server/protocol.js.map +1 -0
  179. package/dist/infrastructure/server/rateLimiter.d.ts +31 -0
  180. package/dist/infrastructure/server/rateLimiter.d.ts.map +1 -0
  181. package/dist/infrastructure/server/rateLimiter.js +79 -0
  182. package/dist/infrastructure/server/rateLimiter.js.map +1 -0
  183. package/dist/infrastructure/server/tcp.d.ts +36 -0
  184. package/dist/infrastructure/server/tcp.d.ts.map +1 -0
  185. package/dist/infrastructure/server/tcp.js +101 -0
  186. package/dist/infrastructure/server/tcp.js.map +1 -0
  187. package/dist/infrastructure/server/types.d.ts +11 -0
  188. package/dist/infrastructure/server/types.d.ts.map +1 -0
  189. package/dist/infrastructure/server/types.js +5 -0
  190. package/dist/infrastructure/server/types.js.map +1 -0
  191. package/dist/main.d.ts +6 -0
  192. package/dist/main.d.ts.map +1 -0
  193. package/dist/main.js +111 -0
  194. package/dist/main.js.map +1 -0
  195. package/dist/shared/hash.d.ts +30 -0
  196. package/dist/shared/hash.d.ts.map +1 -0
  197. package/dist/shared/hash.js +69 -0
  198. package/dist/shared/hash.js.map +1 -0
  199. package/dist/shared/index.d.ts +6 -0
  200. package/dist/shared/index.d.ts.map +1 -0
  201. package/dist/shared/index.js +6 -0
  202. package/dist/shared/index.js.map +1 -0
  203. package/dist/shared/lock.d.ts +70 -0
  204. package/dist/shared/lock.d.ts.map +1 -0
  205. package/dist/shared/lock.js +207 -0
  206. package/dist/shared/lock.js.map +1 -0
  207. package/dist/shared/logger.d.ts +38 -0
  208. package/dist/shared/logger.d.ts.map +1 -0
  209. package/dist/shared/logger.js +74 -0
  210. package/dist/shared/logger.js.map +1 -0
  211. package/dist/shared/serialization.d.ts +23 -0
  212. package/dist/shared/serialization.d.ts.map +1 -0
  213. package/dist/shared/serialization.js +63 -0
  214. package/dist/shared/serialization.js.map +1 -0
  215. package/package.json +82 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 egeominotti
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,640 @@
1
+ <p align="center">
2
+ <img src=".github/banner.svg" alt="bunQ - High-performance job queue for Bun" width="700" />
3
+ </p>
4
+
5
+ <p align="center">
6
+ <a href="https://github.com/egeominotti/bunq/actions"><img src="https://github.com/egeominotti/bunq/actions/workflows/ci.yml/badge.svg" alt="CI"></a>
7
+ <a href="https://github.com/egeominotti/bunq/releases"><img src="https://img.shields.io/github/v/release/egeominotti/bunq" alt="Release"></a>
8
+ <a href="https://github.com/egeominotti/bunq/blob/main/LICENSE"><img src="https://img.shields.io/github/license/egeominotti/bunq" alt="License"></a>
9
+ </p>
10
+
11
+ <p align="center">
12
+ <a href="#features">Features</a> •
13
+ <a href="#sdk">SDK</a> •
14
+ <a href="#quick-start">Quick Start</a> •
15
+ <a href="#installation">Installation</a> •
16
+ <a href="#api-reference">API</a> •
17
+ <a href="#docker">Docker</a>
18
+ </p>
19
+
20
+ <p align="center">
21
+ <a href="https://www.npmjs.com/package/flashq"><img src="https://img.shields.io/npm/v/flashq" alt="npm"></a>
22
+ <a href="https://www.npmjs.com/package/flashq"><img src="https://img.shields.io/npm/dm/flashq" alt="npm downloads"></a>
23
+ </p>
24
+
25
+ ---
26
+
27
+ ## Features
28
+
29
+ - **Blazing Fast** — Built on Bun runtime with native SQLite, optimized for maximum throughput
30
+ - **Persistent Storage** — SQLite with WAL mode for durability and concurrent access
31
+ - **Priority Queues** — FIFO, LIFO, and priority-based job ordering
32
+ - **Delayed Jobs** — Schedule jobs to run at specific times
33
+ - **Cron Scheduling** — Recurring jobs with cron expressions or fixed intervals
34
+ - **Retry & Backoff** — Automatic retries with exponential backoff
35
+ - **Dead Letter Queue** — Failed jobs preserved for inspection and retry
36
+ - **Job Dependencies** — Define parent-child relationships and execution order
37
+ - **Progress Tracking** — Real-time progress updates for long-running jobs
38
+ - **Rate Limiting** — Per-queue rate limits and concurrency control
39
+ - **Webhooks** — HTTP callbacks on job events
40
+ - **Real-time Events** — WebSocket and Server-Sent Events (SSE) support
41
+ - **Prometheus Metrics** — Built-in metrics endpoint for monitoring
42
+ - **Authentication** — Token-based auth for secure access
43
+ - **Dual Protocol** — TCP (high performance) and HTTP/REST (compatibility)
44
+
45
+ ## SDK
46
+
47
+ Install the official TypeScript SDK to use bunQ in your Bun applications.
48
+
49
+ > **Note:** The SDK requires Bun runtime and a running bunQ server.
50
+
51
+ ### Install
52
+
53
+ ```bash
54
+ bun add flashq
55
+ ```
56
+
57
+ ### Basic Usage
58
+
59
+ ```typescript
60
+ import { Queue, Worker } from 'flashq';
61
+
62
+ // Create a queue
63
+ const queue = new Queue('my-queue', {
64
+ connection: { host: 'localhost', port: 6789 }
65
+ });
66
+
67
+ // Add a job
68
+ await queue.add('process-data', { userId: 123, action: 'sync' });
69
+
70
+ // Add with options
71
+ await queue.add('send-email',
72
+ { to: 'user@example.com', subject: 'Hello' },
73
+ {
74
+ priority: 10,
75
+ delay: 5000, // 5 seconds
76
+ attempts: 3,
77
+ backoff: { type: 'exponential', delay: 1000 }
78
+ }
79
+ );
80
+
81
+ // Create a worker
82
+ const worker = new Worker('my-queue', async (job) => {
83
+ console.log('Processing:', job.name, job.data);
84
+
85
+ // Update progress
86
+ await job.updateProgress(50);
87
+
88
+ // Do work...
89
+
90
+ return { success: true };
91
+ }, {
92
+ connection: { host: 'localhost', port: 6789 },
93
+ concurrency: 5
94
+ });
95
+
96
+ // Handle events
97
+ worker.on('completed', (job, result) => {
98
+ console.log(`Job ${job.id} completed:`, result);
99
+ });
100
+
101
+ worker.on('failed', (job, err) => {
102
+ console.error(`Job ${job.id} failed:`, err.message);
103
+ });
104
+ ```
105
+
106
+ ### Cron Jobs
107
+
108
+ ```typescript
109
+ import { Queue } from 'flashq';
110
+
111
+ const queue = new Queue('scheduled', {
112
+ connection: { host: 'localhost', port: 6789 }
113
+ });
114
+
115
+ // Every hour
116
+ await queue.upsertJobScheduler('hourly-report',
117
+ { pattern: '0 * * * *' },
118
+ { name: 'generate-report', data: { type: 'hourly' } }
119
+ );
120
+
121
+ // Every 5 minutes
122
+ await queue.upsertJobScheduler('health-check',
123
+ { every: 300000 },
124
+ { name: 'ping', data: {} }
125
+ );
126
+ ```
127
+
128
+ ### Job Dependencies (Flows)
129
+
130
+ ```typescript
131
+ import { FlowProducer } from 'flashq';
132
+
133
+ const flow = new FlowProducer({
134
+ connection: { host: 'localhost', port: 6789 }
135
+ });
136
+
137
+ // Create a flow with parent-child dependencies
138
+ await flow.add({
139
+ name: 'final-step',
140
+ queueName: 'pipeline',
141
+ data: { step: 'aggregate' },
142
+ children: [
143
+ {
144
+ name: 'step-1',
145
+ queueName: 'pipeline',
146
+ data: { step: 'fetch' }
147
+ },
148
+ {
149
+ name: 'step-2',
150
+ queueName: 'pipeline',
151
+ data: { step: 'transform' }
152
+ }
153
+ ]
154
+ });
155
+ ```
156
+
157
+ ### Real-time Events
158
+
159
+ ```typescript
160
+ import { QueueEvents } from 'flashq';
161
+
162
+ const events = new QueueEvents('my-queue', {
163
+ connection: { host: 'localhost', port: 6789 }
164
+ });
165
+
166
+ events.on('completed', ({ jobId, returnvalue }) => {
167
+ console.log(`Job ${jobId} completed with:`, returnvalue);
168
+ });
169
+
170
+ events.on('failed', ({ jobId, failedReason }) => {
171
+ console.error(`Job ${jobId} failed:`, failedReason);
172
+ });
173
+
174
+ events.on('progress', ({ jobId, data }) => {
175
+ console.log(`Job ${jobId} progress:`, data);
176
+ });
177
+ ```
178
+
179
+ For more examples, see the [SDK documentation](https://www.npmjs.com/package/flashq).
180
+
181
+ ## Quick Start
182
+
183
+ ### Start the Server
184
+
185
+ ```bash
186
+ # Using Bun directly
187
+ bun run src/main.ts
188
+
189
+ # Or with Docker
190
+ docker run -p 6789:6789 -p 6790:6790 ghcr.io/egeominotti/bunq
191
+ ```
192
+
193
+ ### Push a Job (HTTP)
194
+
195
+ ```bash
196
+ curl -X POST http://localhost:6790/queues/emails/jobs \
197
+ -H "Content-Type: application/json" \
198
+ -d '{"data": {"to": "user@example.com", "subject": "Hello"}}'
199
+ ```
200
+
201
+ ### Pull a Job (HTTP)
202
+
203
+ ```bash
204
+ curl http://localhost:6790/queues/emails/jobs
205
+ ```
206
+
207
+ ### Acknowledge Completion
208
+
209
+ ```bash
210
+ curl -X POST http://localhost:6790/jobs/1/ack \
211
+ -H "Content-Type: application/json" \
212
+ -d '{"result": {"sent": true}}'
213
+ ```
214
+
215
+ ## Installation
216
+
217
+ ### From Source
218
+
219
+ ```bash
220
+ git clone https://github.com/egeominotti/bunq.git
221
+ cd bunq
222
+ bun install
223
+ bun run start
224
+ ```
225
+
226
+ ### Build Binary
227
+
228
+ ```bash
229
+ bun run build
230
+ ./dist/bunq
231
+ ```
232
+
233
+ ### Docker
234
+
235
+ ```bash
236
+ docker pull ghcr.io/egeominotti/bunq
237
+ docker run -d \
238
+ -p 6789:6789 \
239
+ -p 6790:6790 \
240
+ -v bunq-data:/app/data \
241
+ ghcr.io/egeominotti/bunq
242
+ ```
243
+
244
+ ### Docker Compose
245
+
246
+ ```yaml
247
+ version: "3.8"
248
+ services:
249
+ bunq:
250
+ image: ghcr.io/egeominotti/bunq
251
+ ports:
252
+ - "6789:6789"
253
+ - "6790:6790"
254
+ volumes:
255
+ - bunq-data:/app/data
256
+ environment:
257
+ - AUTH_TOKENS=your-secret-token
258
+
259
+ volumes:
260
+ bunq-data:
261
+ ```
262
+
263
+ ## Usage
264
+
265
+ ### TCP Protocol (High Performance)
266
+
267
+ Connect via TCP for maximum throughput. Commands are newline-delimited JSON.
268
+
269
+ ```bash
270
+ # Connect with netcat
271
+ nc localhost 6789
272
+
273
+ # Push a job
274
+ {"cmd":"PUSH","queue":"tasks","data":{"action":"process"}}
275
+
276
+ # Pull a job
277
+ {"cmd":"PULL","queue":"tasks"}
278
+
279
+ # Acknowledge
280
+ {"cmd":"ACK","id":"1"}
281
+ ```
282
+
283
+ ### HTTP REST API
284
+
285
+ ```bash
286
+ # Push job
287
+ curl -X POST http://localhost:6790/queues/tasks/jobs \
288
+ -H "Content-Type: application/json" \
289
+ -d '{
290
+ "data": {"action": "process"},
291
+ "priority": 10,
292
+ "delay": 5000,
293
+ "maxAttempts": 5
294
+ }'
295
+
296
+ # Pull job (with timeout)
297
+ curl "http://localhost:6790/queues/tasks/jobs?timeout=30000"
298
+
299
+ # Get job by ID
300
+ curl http://localhost:6790/jobs/123
301
+
302
+ # Fail a job
303
+ curl -X POST http://localhost:6790/jobs/123/fail \
304
+ -H "Content-Type: application/json" \
305
+ -d '{"error": "Processing failed"}'
306
+
307
+ # Get stats
308
+ curl http://localhost:6790/stats
309
+ ```
310
+
311
+ ### WebSocket (Real-time)
312
+
313
+ ```javascript
314
+ const ws = new WebSocket('ws://localhost:6790/ws');
315
+
316
+ ws.onmessage = (event) => {
317
+ const job = JSON.parse(event.data);
318
+ console.log('Job event:', job);
319
+ };
320
+
321
+ // Subscribe to specific queue
322
+ const wsQueue = new WebSocket('ws://localhost:6790/ws/queues/emails');
323
+ ```
324
+
325
+ ### Server-Sent Events (SSE)
326
+
327
+ ```javascript
328
+ const events = new EventSource('http://localhost:6790/events');
329
+
330
+ events.onmessage = (event) => {
331
+ const data = JSON.parse(event.data);
332
+ console.log('Event:', data);
333
+ };
334
+
335
+ // Filter by queue
336
+ const queueEvents = new EventSource('http://localhost:6790/events/queues/emails');
337
+ ```
338
+
339
+ ### Job Options
340
+
341
+ | Option | Type | Default | Description |
342
+ |--------|------|---------|-------------|
343
+ | `data` | any | required | Job payload |
344
+ | `priority` | number | 0 | Higher = processed first |
345
+ | `delay` | number | 0 | Delay in milliseconds |
346
+ | `maxAttempts` | number | 3 | Max retry attempts |
347
+ | `backoff` | number | 1000 | Initial backoff (ms), doubles each retry |
348
+ | `ttl` | number | null | Time-to-live in milliseconds |
349
+ | `timeout` | number | null | Job processing timeout |
350
+ | `uniqueKey` | string | null | Deduplication key |
351
+ | `jobId` | string | null | Custom job identifier |
352
+ | `dependsOn` | string[] | [] | Job IDs that must complete first |
353
+ | `tags` | string[] | [] | Tags for filtering |
354
+ | `groupId` | string | null | Group identifier |
355
+ | `lifo` | boolean | false | Last-in-first-out ordering |
356
+ | `removeOnComplete` | boolean | false | Auto-delete on completion |
357
+ | `removeOnFail` | boolean | false | Auto-delete on failure |
358
+
359
+ ### Cron Jobs
360
+
361
+ ```bash
362
+ # Cron expression (every hour)
363
+ curl -X POST http://localhost:6790/cron \
364
+ -d '{"cmd":"Cron","name":"hourly-cleanup","queue":"maintenance","data":{"task":"cleanup"},"schedule":"0 * * * *"}'
365
+
366
+ # Fixed interval (every 5 minutes)
367
+ curl -X POST http://localhost:6790/cron \
368
+ -d '{"cmd":"Cron","name":"health-check","queue":"monitoring","data":{"check":"ping"},"repeatEvery":300000}'
369
+
370
+ # With execution limit
371
+ curl -X POST http://localhost:6790/cron \
372
+ -d '{"cmd":"Cron","name":"one-time-migration","queue":"migrations","data":{},"repeatEvery":0,"maxLimit":1}'
373
+ ```
374
+
375
+ ## API Reference
376
+
377
+ ### Core Operations
378
+
379
+ | Command | Description |
380
+ |---------|-------------|
381
+ | `PUSH` | Add a job to a queue |
382
+ | `PUSHB` | Batch push multiple jobs |
383
+ | `PULL` | Get the next job from a queue |
384
+ | `PULLB` | Batch pull multiple jobs |
385
+ | `ACK` | Mark job as completed |
386
+ | `ACKB` | Batch acknowledge jobs |
387
+ | `FAIL` | Mark job as failed |
388
+
389
+ ### Query Operations
390
+
391
+ | Command | Description |
392
+ |---------|-------------|
393
+ | `GetJob` | Get job by ID |
394
+ | `GetState` | Get job state |
395
+ | `GetResult` | Get job result |
396
+ | `GetJobs` | List jobs with filters |
397
+ | `GetJobCounts` | Count jobs by state |
398
+ | `GetJobByCustomId` | Find job by custom ID |
399
+ | `GetProgress` | Get job progress |
400
+ | `GetLogs` | Get job logs |
401
+
402
+ ### Job Management
403
+
404
+ | Command | Description |
405
+ |---------|-------------|
406
+ | `Cancel` | Cancel a pending job |
407
+ | `Progress` | Update job progress |
408
+ | `Update` | Update job data |
409
+ | `ChangePriority` | Change job priority |
410
+ | `Promote` | Move delayed job to waiting |
411
+ | `MoveToDelayed` | Delay a waiting job |
412
+ | `Discard` | Discard a job |
413
+ | `Heartbeat` | Send job heartbeat |
414
+ | `AddLog` | Add log entry to job |
415
+
416
+ ### Queue Control
417
+
418
+ | Command | Description |
419
+ |---------|-------------|
420
+ | `Pause` | Pause queue processing |
421
+ | `Resume` | Resume queue processing |
422
+ | `IsPaused` | Check if queue is paused |
423
+ | `Drain` | Remove all waiting jobs |
424
+ | `Obliterate` | Remove all queue data |
425
+ | `Clean` | Remove old jobs |
426
+ | `ListQueues` | List all queues |
427
+ | `RateLimit` | Set queue rate limit |
428
+ | `SetConcurrency` | Set max concurrent jobs |
429
+
430
+ ### Dead Letter Queue
431
+
432
+ | Command | Description |
433
+ |---------|-------------|
434
+ | `Dlq` | Get failed jobs |
435
+ | `RetryDlq` | Retry failed jobs |
436
+ | `PurgeDlq` | Clear failed jobs |
437
+
438
+ ### Scheduling
439
+
440
+ | Command | Description |
441
+ |---------|-------------|
442
+ | `Cron` | Create/update cron job |
443
+ | `CronDelete` | Delete cron job |
444
+ | `CronList` | List all cron jobs |
445
+
446
+ ### Workers & Webhooks
447
+
448
+ | Command | Description |
449
+ |---------|-------------|
450
+ | `RegisterWorker` | Register a worker |
451
+ | `UnregisterWorker` | Unregister a worker |
452
+ | `ListWorkers` | List active workers |
453
+ | `AddWebhook` | Add webhook endpoint |
454
+ | `RemoveWebhook` | Remove webhook |
455
+ | `ListWebhooks` | List webhooks |
456
+
457
+ ### Monitoring
458
+
459
+ | Command | Description |
460
+ |---------|-------------|
461
+ | `Stats` | Get server statistics |
462
+ | `Metrics` | Get job metrics |
463
+ | `Prometheus` | Prometheus format metrics |
464
+
465
+ ## Configuration
466
+
467
+ ### Environment Variables
468
+
469
+ | Variable | Default | Description |
470
+ |----------|---------|-------------|
471
+ | `TCP_PORT` | 6789 | TCP protocol port |
472
+ | `HTTP_PORT` | 6790 | HTTP/WebSocket port |
473
+ | `HOST` | 0.0.0.0 | Bind address |
474
+ | `AUTH_TOKENS` | - | Comma-separated auth tokens |
475
+ | `DATA_PATH` | - | SQLite database path (in-memory if not set) |
476
+ | `CORS_ALLOW_ORIGIN` | * | Allowed CORS origins |
477
+
478
+ ### Authentication
479
+
480
+ Enable authentication by setting `AUTH_TOKENS`:
481
+
482
+ ```bash
483
+ AUTH_TOKENS=token1,token2 bun run start
484
+ ```
485
+
486
+ **HTTP:**
487
+ ```bash
488
+ curl -H "Authorization: Bearer token1" http://localhost:6790/stats
489
+ ```
490
+
491
+ **TCP:**
492
+ ```json
493
+ {"cmd":"Auth","token":"token1"}
494
+ ```
495
+
496
+ **WebSocket:**
497
+ ```json
498
+ {"cmd":"Auth","token":"token1"}
499
+ ```
500
+
501
+ ## Monitoring
502
+
503
+ ### Health Check
504
+
505
+ ```bash
506
+ curl http://localhost:6790/health
507
+ # {"ok":true,"status":"healthy"}
508
+ ```
509
+
510
+ ### Prometheus Metrics
511
+
512
+ ```bash
513
+ curl http://localhost:6790/prometheus
514
+ ```
515
+
516
+ Metrics include:
517
+ - `bunq_jobs_total{queue,state}` — Job counts by state
518
+ - `bunq_jobs_processed_total{queue}` — Total processed jobs
519
+ - `bunq_jobs_failed_total{queue}` — Total failed jobs
520
+ - `bunq_queue_latency_seconds{queue}` — Processing latency
521
+
522
+ ### Statistics
523
+
524
+ ```bash
525
+ curl http://localhost:6790/stats
526
+ ```
527
+
528
+ ```json
529
+ {
530
+ "ok": true,
531
+ "stats": {
532
+ "waiting": 150,
533
+ "active": 10,
534
+ "delayed": 25,
535
+ "completed": 10000,
536
+ "failed": 50,
537
+ "dlq": 5,
538
+ "totalPushed": 10235,
539
+ "totalPulled": 10085,
540
+ "totalCompleted": 10000,
541
+ "totalFailed": 50
542
+ }
543
+ }
544
+ ```
545
+
546
+ ## Docker
547
+
548
+ ### Build
549
+
550
+ ```bash
551
+ docker build -t bunq .
552
+ ```
553
+
554
+ ### Run
555
+
556
+ ```bash
557
+ # Basic
558
+ docker run -p 6789:6789 -p 6790:6790 bunq
559
+
560
+ # With persistence
561
+ docker run -p 6789:6789 -p 6790:6790 \
562
+ -v bunq-data:/app/data \
563
+ -e DATA_PATH=/app/data/bunq.db \
564
+ bunq
565
+
566
+ # With authentication
567
+ docker run -p 6789:6789 -p 6790:6790 \
568
+ -e AUTH_TOKENS=secret1,secret2 \
569
+ bunq
570
+ ```
571
+
572
+ ### Docker Compose
573
+
574
+ ```bash
575
+ # Production
576
+ docker compose up -d
577
+
578
+ # Development (hot reload)
579
+ docker compose --profile dev up bunq-dev
580
+ ```
581
+
582
+ ## Architecture
583
+
584
+ ```
585
+ ┌─────────────────────────────────────────────────────────────┐
586
+ │ bunQ Server │
587
+ ├─────────────────────────────────────────────────────────────┤
588
+ │ HTTP/WS (Bun.serve) │ TCP Protocol (Bun.listen) │
589
+ ├─────────────────────────────────────────────────────────────┤
590
+ │ Core Engine │
591
+ │ ┌──────────┐ ┌──────────┐ ┌───────────┐ ┌──────────┐ │
592
+ │ │ Queues │ │ Workers │ │ Scheduler │ │ DLQ │ │
593
+ │ │ (32 shards) │ │ │ (Cron) │ │ │ │
594
+ │ └──────────┘ └──────────┘ └───────────┘ └──────────┘ │
595
+ ├─────────────────────────────────────────────────────────────┤
596
+ │ SQLite (WAL mode, 256MB mmap) │
597
+ └─────────────────────────────────────────────────────────────┘
598
+ ```
599
+
600
+ ### Performance Optimizations
601
+
602
+ - **32 Shards** — Lock contention minimized with FNV-1a hash distribution
603
+ - **WAL Mode** — Concurrent reads during writes
604
+ - **Memory-mapped I/O** — 256MB mmap for fast access
605
+ - **Batch Operations** — Bulk inserts and updates
606
+ - **Bounded Collections** — Automatic memory cleanup
607
+
608
+ ## Contributing
609
+
610
+ Contributions are welcome! Please read our contributing guidelines before submitting PRs.
611
+
612
+ ```bash
613
+ # Install dependencies
614
+ bun install
615
+
616
+ # Run tests
617
+ bun test
618
+
619
+ # Run linter
620
+ bun run lint
621
+
622
+ # Format code
623
+ bun run format
624
+
625
+ # Type check
626
+ bun run typecheck
627
+
628
+ # Run all checks
629
+ bun run check
630
+ ```
631
+
632
+ ## License
633
+
634
+ MIT License — see [LICENSE](LICENSE) for details.
635
+
636
+ ---
637
+
638
+ <p align="center">
639
+ Built with <a href="https://bun.sh">Bun</a> 🥟
640
+ </p>
@@ -0,0 +1,19 @@
1
+ /**
2
+ * DLQ Manager
3
+ * Dead Letter Queue operations
4
+ */
5
+ import type { Job, JobId } from '../domain/types/job';
6
+ import type { JobLocation } from '../domain/types/queue';
7
+ import type { Shard } from '../domain/queue/shard';
8
+ /** Context for DLQ operations */
9
+ export interface DlqContext {
10
+ shards: Shard[];
11
+ jobIndex: Map<JobId, JobLocation>;
12
+ }
13
+ /** Get jobs from DLQ */
14
+ export declare function getDlqJobs(queue: string, ctx: DlqContext, count?: number): Job[];
15
+ /** Retry jobs from DLQ */
16
+ export declare function retryDlqJobs(queue: string, ctx: DlqContext, jobId?: JobId): number;
17
+ /** Purge all jobs from DLQ */
18
+ export declare function purgeDlqJobs(queue: string, ctx: DlqContext): number;
19
+ //# sourceMappingURL=dlqManager.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dlqManager.d.ts","sourceRoot":"","sources":["../../src/application/dlqManager.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,GAAG,EAAE,KAAK,EAAE,MAAM,qBAAqB,CAAC;AACtD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AACzD,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,uBAAuB,CAAC;AAGnD,iCAAiC;AACjC,MAAM,WAAW,UAAU;IACzB,MAAM,EAAE,KAAK,EAAE,CAAC;IAChB,QAAQ,EAAE,GAAG,CAAC,KAAK,EAAE,WAAW,CAAC,CAAC;CACnC;AAED,wBAAwB;AACxB,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,UAAU,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,GAAG,EAAE,CAIhF;AAED,0BAA0B;AAC1B,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,UAAU,EAAE,KAAK,CAAC,EAAE,KAAK,GAAG,MAAM,CA6BlF;AAED,8BAA8B;AAC9B,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,UAAU,GAAG,MAAM,CAGnE"}