lonnymq 0.0.26 → 0.0.28
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.
- package/README.md +78 -51
- package/dist/index.cjs +32 -43
- package/dist/index.d.ts +8 -14
- package/dist/index.js +58 -69
- package/package.json +3 -2
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# LonnyMQ
|
|
2
2
|
|
|
3
|
-
A high-performance, multi-tenant PostgreSQL message queue implementation for Node.js/TypeScript.
|
|
3
|
+
A high-performance, multi-tenant PostgreSQL message queue implementation for Node.js/TypeScript. Docs can be found [here](https://tlonny.github.io/lonnymq)
|
|
4
4
|
|
|
5
5
|
## Features
|
|
6
6
|
|
|
@@ -35,14 +35,16 @@ for (const sql of queue.install()) {
|
|
|
35
35
|
for (let ix = 0; ix < 500; ix += 1) {
|
|
36
36
|
await queue.message.create({
|
|
37
37
|
databaseClient,
|
|
38
|
-
content: Buffer.from("Hello")
|
|
39
|
-
lockMs: 30_000
|
|
38
|
+
content: Buffer.from("Hello")
|
|
40
39
|
})
|
|
41
40
|
}
|
|
42
41
|
|
|
43
42
|
// Process messages
|
|
44
43
|
while (true) {
|
|
45
|
-
const dequeueResult = await queue.dequeue({
|
|
44
|
+
const dequeueResult = await queue.dequeue({
|
|
45
|
+
databaseClient,
|
|
46
|
+
lockMs: 30_000
|
|
47
|
+
})
|
|
46
48
|
if (dequeueResult.resultType === "MESSAGE_NOT_AVAILABLE") {
|
|
47
49
|
break
|
|
48
50
|
}
|
|
@@ -87,18 +89,16 @@ await queue
|
|
|
87
89
|
|
|
88
90
|
## Message Creation
|
|
89
91
|
|
|
90
|
-
You can add a message to the queue using the `create` function. By default, messages are assigned to a
|
|
92
|
+
You can add a message to the queue using the `create` function. By default, messages are assigned to a unique channel, resulting in basic FIFO behaviour.
|
|
91
93
|
|
|
92
94
|
```typescript
|
|
93
95
|
await queue.message.create({
|
|
94
96
|
databaseClient,
|
|
95
97
|
content: Buffer.from("Hello, world"),
|
|
96
|
-
lockMs: 30000,
|
|
97
|
-
delayMs: 5000
|
|
98
98
|
})
|
|
99
99
|
```
|
|
100
100
|
|
|
101
|
-
If you need to assign messages to specific channels (for example, to take advantage of concurrency or rate limiting features), you can specify the channel explicitly:
|
|
101
|
+
If you need to assign messages to specific channels (for example, to take advantage of fairness, concurrency or rate limiting features), you can specify the channel explicitly:
|
|
102
102
|
|
|
103
103
|
```typescript
|
|
104
104
|
await queue
|
|
@@ -106,22 +106,21 @@ await queue
|
|
|
106
106
|
.message
|
|
107
107
|
.create({
|
|
108
108
|
databaseClient,
|
|
109
|
-
content: Buffer.from("Hello, world")
|
|
110
|
-
lockMs: 30000,
|
|
111
|
-
delayMs: 5000
|
|
109
|
+
content: Buffer.from("Hello, world")
|
|
112
110
|
})
|
|
113
111
|
```
|
|
114
112
|
|
|
115
|
-
The `lockMs` parameter is required and specifies how long a message will remain exclusively locked after being dequeued. While locked, the message is **not available** for subsequent `dequeue()` calls, preventing duplicate processing. If your process crashes or takes longer than expected, the message will automatically become available for dequeue again after the lock expires.
|
|
116
|
-
|
|
117
113
|
The `delayMs` parameter is optional and allows you to delay when the message becomes available for processing.
|
|
118
114
|
|
|
119
115
|
## Message Processing
|
|
120
116
|
|
|
121
|
-
Messages can be fetched for processing by calling `dequeue` on the `Queue` - this locks the message. Once processing is complete, messages must be "finalized" via **deletion** or **deferral** (for further processing in the future).
|
|
117
|
+
Messages can be fetched for processing by calling `dequeue` on the `Queue` - this locks the message for a specified duration. Once processing is complete, messages must be "finalized" via **deletion** or **deferral** (for further processing in the future).
|
|
122
118
|
|
|
123
119
|
```typescript
|
|
124
|
-
const dequeueResult = await queue.dequeue({
|
|
120
|
+
const dequeueResult = await queue.dequeue({
|
|
121
|
+
databaseClient,
|
|
122
|
+
lockMs: 60_000
|
|
123
|
+
})
|
|
125
124
|
|
|
126
125
|
if (dequeueResult.resultType === "MESSAGE_DEQUEUED") {
|
|
127
126
|
const { message } = dequeueResult
|
|
@@ -157,15 +156,50 @@ if (dequeueResult.resultType === "MESSAGE_DEQUEUED") {
|
|
|
157
156
|
}
|
|
158
157
|
```
|
|
159
158
|
|
|
159
|
+
The `lockMs` parameter on `dequeue()` specifies how long a message will remain exclusively locked after being dequeued. While locked, the message is **not available** for subsequent `dequeue()` calls, preventing duplicate processing. If your process crashes or takes longer than expected, the message will automatically become available for dequeue again after the lock expires.
|
|
160
|
+
|
|
160
161
|
When deferring a message, you can optionally specify `delayMs` and `state` arguments. The `delayMs` parameter tells the queue how long to wait before making the message available for reprocessing, and `state` allows you to "save your work" and implement durable and/or repeating/scheduled tasks.
|
|
161
162
|
|
|
162
163
|
**Note:** The above shows just one processing pattern (defer on failure with retry limits). You have complete flexibility in how you handle message processing - you might delete messages immediately, defer them unconditionally, implement different retry strategies based on error types, or use the message metadata (attempts, state, channel) to make sophisticated routing decisions.
|
|
163
164
|
|
|
164
|
-
###
|
|
165
|
+
### Extending Message Locks with Heartbeats
|
|
165
166
|
|
|
166
|
-
|
|
167
|
+
For messages that take a long time to process, setting a large initial lock is far from ideal. A crash shortly after message dequeue will result in channel throughput being degraded for a significant time (if the channel is concurrency-constrained). To mitigate this, you can set a short initial lock time that can be periodically renewed during message processing via a heartbeat:
|
|
168
|
+
|
|
169
|
+
```typescript
|
|
170
|
+
const dequeueResult = await queue.dequeue({
|
|
171
|
+
databaseClient,
|
|
172
|
+
lockMs: 30_000
|
|
173
|
+
})
|
|
167
174
|
|
|
168
|
-
|
|
175
|
+
if (dequeueResult.resultType === "MESSAGE_DEQUEUED") {
|
|
176
|
+
const { message } = dequeueResult
|
|
177
|
+
|
|
178
|
+
// Start long-running process
|
|
179
|
+
const longTask = processLongRunningTask(message.content)
|
|
180
|
+
|
|
181
|
+
// Set up heartbeat to extend lock every 20 seconds
|
|
182
|
+
const heartbeatInterval = setInterval(async () => {
|
|
183
|
+
await message.heartbeat({
|
|
184
|
+
databaseClient,
|
|
185
|
+
lockMs: 30_000
|
|
186
|
+
})
|
|
187
|
+
}, 20_000)
|
|
188
|
+
|
|
189
|
+
try {
|
|
190
|
+
await longTask
|
|
191
|
+
await message.delete({ databaseClient })
|
|
192
|
+
} catch (error) {
|
|
193
|
+
await message.defer({ databaseClient, delayMs: 60_000 })
|
|
194
|
+
} finally {
|
|
195
|
+
clearInterval(heartbeatInterval)
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
### Graceful Shutdowns and Message Recovery
|
|
201
|
+
|
|
202
|
+
If your program ends unexpectedly, messages that are currently being processed may become "orphaned" in a locked state - causing channel blockages and reducing throughput until the lock expires. To mitigate this problem, it's essential that you shut down gracefully by catching unhandled exceptions and signals (i.e., `SIGINT`/`SIGTERM`) and finalize all outstanding messages before exiting.
|
|
169
203
|
|
|
170
204
|
## Events
|
|
171
205
|
|
|
@@ -185,21 +219,37 @@ const install = queue.install({ eventChannel: "EVENTS"})
|
|
|
185
219
|
|
|
186
220
|
The simplest approach for processing messages is to call `dequeue` in a loop, backing off with a sleep when no messages are available. The downside of this approach is that we lose reactivity as we increase the polling timeout interval.
|
|
187
221
|
|
|
188
|
-
|
|
222
|
+
```typescript
|
|
223
|
+
// Basic polling approach
|
|
224
|
+
while (true) {
|
|
225
|
+
const result = await queue.dequeue({ databaseClient, lockMs: 30_000 })
|
|
226
|
+
|
|
227
|
+
if (result.resultType === "MESSAGE_NOT_AVAILABLE") {
|
|
228
|
+
await sleep(5_000)
|
|
229
|
+
continue
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
// Process message...
|
|
233
|
+
await processMessage(result.message)
|
|
234
|
+
await result.message.delete({ databaseClient })
|
|
235
|
+
}
|
|
236
|
+
```
|
|
189
237
|
|
|
190
|
-
|
|
238
|
+
To improve reactivity, you can use the events system to track when new messages become available. By listening for `MESSAGE_CREATED` and `MESSAGE_DEFERRED` events and tracking their `delayMs`, you can determine the optimal time to retry dequeuing:
|
|
191
239
|
|
|
192
240
|
```typescript
|
|
193
241
|
// LISTEN/NOTIFY only works with a single connection - not on a connection pool.
|
|
194
242
|
const client = await databaseClient.connect()
|
|
195
243
|
await client.query(`LISTEN "EVENTS"`)
|
|
244
|
+
|
|
245
|
+
let nextWakeTime = Date.now()
|
|
246
|
+
|
|
196
247
|
client.on("notification", (msg) => {
|
|
197
|
-
if (msg.channel === "EVENTS") {
|
|
248
|
+
if (msg.channel === "EVENTS") {
|
|
198
249
|
const event = queueEventDecode(msg.payload as string)
|
|
199
|
-
if(event.eventType === "MESSAGE_CREATED") {
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
console.log(`Should wake in ${event.delayMs} ms`)
|
|
250
|
+
if (event.eventType === "MESSAGE_CREATED" || event.eventType === "MESSAGE_DEFERRED") {
|
|
251
|
+
const messageAvailableAt = Date.now() + event.delayMs
|
|
252
|
+
nextWakeTime = Math.min(nextWakeTime, messageAvailableAt)
|
|
203
253
|
}
|
|
204
254
|
}
|
|
205
255
|
})
|
|
@@ -209,28 +259,6 @@ client.on("notification", (msg) => {
|
|
|
209
259
|
|
|
210
260
|
The `MESSAGE_DELETED` event can be used to create coordination patterns where one part of your application waits for an unrelated job to complete. By listening for deletion events on specific message IDs, you can implement blocking operations that wait for background work to finish.
|
|
211
261
|
|
|
212
|
-
```typescript
|
|
213
|
-
const client = await databaseClient.connect()
|
|
214
|
-
await client.query(`LISTEN "EVENTS"`)
|
|
215
|
-
|
|
216
|
-
const wait = (messageId: string) : Promise<void> => {
|
|
217
|
-
return new Promise((resolve) => {
|
|
218
|
-
const handler = (msg) => {
|
|
219
|
-
if (msg.channel === "EVENTS") {
|
|
220
|
-
const event = queueEventDecode(msg.payload as string)
|
|
221
|
-
if (event.eventType === "MESSAGE_DELETED" && event.id === messageId) {
|
|
222
|
-
client.off("notification", handler)
|
|
223
|
-
resolve()
|
|
224
|
-
}
|
|
225
|
-
}
|
|
226
|
-
}
|
|
227
|
-
client.on("notification", handler)
|
|
228
|
-
})
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
await wait(messageId)
|
|
232
|
-
```
|
|
233
|
-
|
|
234
262
|
## Deadlocks
|
|
235
263
|
|
|
236
264
|
If all queue actions are isolated to their own transaction, there is zero risk of deadlocks occurring. That being said, it is *possible* to safely bulk-perform the following actions within a single transaction if we ensure they are performed in a consistent ordering with respect to the target channel name:
|
|
@@ -244,6 +272,7 @@ Beyond the actions specified above, it is manifestly **unsafe** to bulk-perform
|
|
|
244
272
|
- Message dequeue
|
|
245
273
|
- Message defer
|
|
246
274
|
- Message delete
|
|
275
|
+
- Message heartbeat
|
|
247
276
|
|
|
248
277
|
## Database Clients
|
|
249
278
|
|
|
@@ -263,12 +292,10 @@ For database clients that don't match the expected interface exactly, LonnyMQ pr
|
|
|
263
292
|
|
|
264
293
|
```typescript
|
|
265
294
|
import { Queue } from "lonnymq"
|
|
266
|
-
import { Pool } from "pg"
|
|
267
295
|
|
|
268
|
-
const
|
|
269
|
-
const queue = new Queue({
|
|
296
|
+
const queue = new Queue<NonCompliantDatabaseClient>({
|
|
270
297
|
schema: "lonny",
|
|
271
|
-
adaptor: (client) => ({
|
|
298
|
+
adaptor: (client : NonCompliantDatabaseClient) => ({
|
|
272
299
|
query: async (sql, params) => {
|
|
273
300
|
// Adapt the client's interface to match DatabaseClient
|
|
274
301
|
const result = await client.executeQuery(sql, params)
|
package/dist/index.cjs
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
var{defineProperty:h,getOwnPropertyNames:k,getOwnPropertyDescriptor:P}=Object,Q=Object.prototype.hasOwnProperty;var M=new WeakMap,V=(e)=>{var t=M.get(e),a;if(t)return t;if(t=h({},"__esModule",{value:!0}),e&&typeof e==="object"||typeof e==="function")k(e).map((r)=>!Q.call(t,r)&&h(t,r,{get:()=>e[r],enumerable:!(a=P(e,r))||a.enumerable}));return M.set(e,t),t};var W=(e,t)=>{for(var a in t)h(e,a,{get:t[a],enumerable:!0,configurable:!0,set:(r)=>t[a]=()=>r})};var le={};W(le,{queueEventDecode:()=>v,Queue:()=>y,MessageHeartbeatCommand:()=>d,MessageDequeueCommand:()=>m,MessageDeleteCommand:()=>
|
|
1
|
+
var{defineProperty:h,getOwnPropertyNames:k,getOwnPropertyDescriptor:P}=Object,Q=Object.prototype.hasOwnProperty;var M=new WeakMap,V=(e)=>{var t=M.get(e),a;if(t)return t;if(t=h({},"__esModule",{value:!0}),e&&typeof e==="object"||typeof e==="function")k(e).map((r)=>!Q.call(t,r)&&h(t,r,{get:()=>e[r],enumerable:!(a=P(e,r))||a.enumerable}));return M.set(e,t),t};var W=(e,t)=>{for(var a in t)h(e,a,{get:t[a],enumerable:!0,configurable:!0,set:(r)=>t[a]=()=>r})};var le={};W(le,{queueEventDecode:()=>v,Queue:()=>y,MessageHeartbeatCommand:()=>d,MessageDequeueCommand:()=>m,MessageDeleteCommand:()=>u,MessageDeferCommand:()=>i,MessageCreateCommand:()=>l,ChannelPolicySetCommand:()=>c,ChannelPolicyClearCommand:()=>o});module.exports=V(le);var I=(e)=>{return e*1000};var T=I(0);var v=(e)=>{let t=JSON.parse(e);if(t.type===0)return{eventType:"MESSAGE_CREATED",id:t.id,delayMs:t.delay_ms};else if(t.type===1)return{eventType:"MESSAGE_DELETED",id:t.id};else if(t.type===2)return{eventType:"MESSAGE_DEFERRED",id:t.id,delayMs:t.delay_ms};else throw new Error("Unknown event type")};var E=(e)=>({nodeType:"VALUE",value:e}),s=(e)=>({nodeType:"REF",value:e}),Y=(e)=>({nodeType:"RAW",value:e}),z=(e)=>{return`'${e.replace(/'/g,"''")}'`},X=(e)=>{if(e===null)return"NULL";else if(typeof e==="string")return z(e);else if(typeof e==="number")return e.toString();else if(typeof e==="boolean")return e?"TRUE":"FALSE";else if(e instanceof Date)return`'${e.toISOString()}'`;else if(typeof e==="bigint")return e.toString();else throw new Error(`Unsupported value type: ${typeof e}`)},J=(e)=>{return`"${e.replace(/"/g,'""')}"`},j=(e)=>{if(e.nodeType==="VALUE")return X(e.value);else if(e.nodeType==="REF")return J(e.value);else if(e.nodeType==="RAW")return e.value;else throw new Error("Unsupported SQL node type")};var n=(e,...t)=>{let a=[];for(let r=0;r<e.length;r+=1)if(a.push(e[r]),r<t.length)a.push(j(t[r]));return Y(a.join(""))};class o{schema;channelName;createdAt;constructor(e){this.schema=e.schema,this.channelName=e.channelName,this.createdAt=new Date}async execute(e){await e.query(n`
|
|
2
2
|
SELECT 1 FROM ${s(this.schema)}."channel_policy_clear"(
|
|
3
3
|
$1
|
|
4
4
|
)
|
|
5
|
-
`.value,[this.channelName])}}class
|
|
5
|
+
`.value,[this.channelName])}}class c{schema;channelName;maxConcurrency;releaseIntervalMs;createdAt;constructor(e){this.schema=e.schema,this.channelName=e.channelName;let t=e.maxConcurrency??null;this.maxConcurrency=t!==null?Math.max(0,t):null;let a=e.releaseIntervalMs??null;this.releaseIntervalMs=a!==null?Math.max(0,a):null,this.createdAt=new Date}async execute(e){await e.query(n`
|
|
6
6
|
SELECT 1 FROM ${s(this.schema)}."channel_policy_set"(
|
|
7
7
|
$1,
|
|
8
8
|
$2::INTEGER,
|
|
@@ -17,19 +17,19 @@ var{defineProperty:h,getOwnPropertyNames:k,getOwnPropertyDescriptor:P}=Object,Q=
|
|
|
17
17
|
$2,
|
|
18
18
|
$3::BIGINT
|
|
19
19
|
)
|
|
20
|
-
`.value,[this.channelName,this.content,this.delayMs]).then((a)=>a.rows[0]);if(t.result_code===0)return{resultType:"MESSAGE_CREATED",
|
|
20
|
+
`.value,[this.channelName,this.content,this.delayMs]).then((a)=>a.rows[0]);if(t.result_code===0)return{resultType:"MESSAGE_CREATED",id:t.metadata.id,channelSize:t.metadata.channel_size};else throw new Error("Unexpected result code")}}class m{schema;lockMs;constructor(e){this.schema=e.schema,this.lockMs=e.lockMs}async execute(e){let t=await e.query(n`
|
|
21
21
|
SELECT
|
|
22
22
|
result_code,
|
|
23
23
|
metadata,
|
|
24
24
|
content,
|
|
25
25
|
state
|
|
26
26
|
FROM ${s(this.schema)}."message_dequeue"($1::BIGINT)
|
|
27
|
-
`.value,[this.lockMs]).then((a)=>a.rows[0]);if(t.result_code===0)return{resultType:"MESSAGE_NOT_AVAILABLE"
|
|
27
|
+
`.value,[this.lockMs]).then((a)=>a.rows[0]);if(t.result_code===0)return{resultType:"MESSAGE_NOT_AVAILABLE"};else if(t.result_code===1)return{resultType:"MESSAGE_DEQUEUED",id:t.metadata.id,channelName:t.metadata.channel_name,isUnlocked:t.metadata.is_unlocked,content:t.content,state:t.state,numAttempts:t.metadata.num_attempts};else throw new Error("Unexpected dequeue result")}}class u{schema;id;numAttempts;constructor(e){this.schema=e.schema,this.id=e.id,this.numAttempts=e.numAttempts}async execute(e){let t=await e.query(n`
|
|
28
28
|
SELECT * FROM ${s(this.schema)}."message_delete"(
|
|
29
29
|
$1,
|
|
30
30
|
$2::BIGINT
|
|
31
31
|
)
|
|
32
|
-
`.value,[this.id,this.numAttempts]).then((a)=>a.rows[0]);if(t.result_code===0)return{resultType:"MESSAGE_NOT_FOUND"};else if(t.result_code===1)return{resultType:"STATE_INVALID"};else if(t.result_code===2)return{resultType:"MESSAGE_DELETED"};else throw new Error("Unexpected result")}}class
|
|
32
|
+
`.value,[this.id,this.numAttempts]).then((a)=>a.rows[0]);if(t.result_code===0)return{resultType:"MESSAGE_NOT_FOUND"};else if(t.result_code===1)return{resultType:"STATE_INVALID"};else if(t.result_code===2)return{resultType:"MESSAGE_DELETED"};else throw new Error("Unexpected result")}}class i{schema;id;numAttempts;delayMs;state;constructor(e){let t=e.delayMs===void 0?T:e.delayMs;this.schema=e.schema,this.numAttempts=e.numAttempts,this.id=e.id,this.delayMs=t,this.state=e.state??null}async execute(e){let t=await e.query(n`
|
|
33
33
|
SELECT * FROM ${s(this.schema)}."message_defer"(
|
|
34
34
|
$1,
|
|
35
35
|
$2::BIGINT,
|
|
@@ -67,8 +67,8 @@ var{defineProperty:h,getOwnPropertyNames:k,getOwnPropertyDescriptor:P}=Object,Q=
|
|
|
67
67
|
"message_id" UUID,
|
|
68
68
|
"message_seq_no" BIGINT,
|
|
69
69
|
"message_dequeue_at" TIMESTAMP,
|
|
70
|
-
"
|
|
71
|
-
"
|
|
70
|
+
"dequeue_prev_at" TIMESTAMP NOT NULL,
|
|
71
|
+
"dequeue_next_at" TIMESTAMP NULL,
|
|
72
72
|
"created_at" TIMESTAMP NOT NULL,
|
|
73
73
|
PRIMARY KEY ("id")
|
|
74
74
|
);
|
|
@@ -78,10 +78,10 @@ var{defineProperty:h,getOwnPropertyNames:k,getOwnPropertyDescriptor:P}=Object,Q=
|
|
|
78
78
|
`,n`
|
|
79
79
|
CREATE INDEX ${s(a)}
|
|
80
80
|
ON ${s(e.schema)}."channel_state" (
|
|
81
|
-
"
|
|
81
|
+
"dequeue_next_at" ASC
|
|
82
82
|
) WHERE "message_id" IS NOT NULL
|
|
83
83
|
AND ("max_concurrency" IS NULL OR "current_concurrency" < "max_concurrency");
|
|
84
|
-
`]}};var __filename="/home/runner/work/lonnymq/lonnymq/src/install/02-table-message.ts",
|
|
84
|
+
`]}};var __filename="/home/runner/work/lonnymq/lonnymq/src/install/02-table-message.ts",q={name:_(__filename),sql:(e)=>{return[n`
|
|
85
85
|
CREATE TABLE ${s(e.schema)}."message" (
|
|
86
86
|
"id" UUID NOT NULL,
|
|
87
87
|
"channel_name" TEXT NOT NULL,
|
|
@@ -107,7 +107,7 @@ var{defineProperty:h,getOwnPropertyNames:k,getOwnPropertyDescriptor:P}=Object,Q=
|
|
|
107
107
|
ON ${s(e.schema)}."message" (
|
|
108
108
|
"unlock_at" ASC
|
|
109
109
|
) WHERE "is_locked";
|
|
110
|
-
`]}};var __filename="/home/runner/work/lonnymq/lonnymq/src/install/03-function-message-create.ts",
|
|
110
|
+
`]}};var __filename="/home/runner/work/lonnymq/lonnymq/src/install/03-function-message-create.ts",G={name:_(__filename),sql:(e)=>{return[n`
|
|
111
111
|
CREATE FUNCTION ${s(e.schema)}."message_create" (
|
|
112
112
|
p_channel_name TEXT,
|
|
113
113
|
p_content BYTEA,
|
|
@@ -160,7 +160,7 @@ var{defineProperty:h,getOwnPropertyNames:k,getOwnPropertyDescriptor:P}=Object,Q=
|
|
|
160
160
|
"current_size",
|
|
161
161
|
"max_concurrency",
|
|
162
162
|
"release_interval_ms",
|
|
163
|
-
"
|
|
163
|
+
"dequeue_prev_at",
|
|
164
164
|
"created_at"
|
|
165
165
|
) VALUES (
|
|
166
166
|
p_channel_name,
|
|
@@ -178,7 +178,7 @@ var{defineProperty:h,getOwnPropertyNames:k,getOwnPropertyDescriptor:P}=Object,Q=
|
|
|
178
178
|
"current_size",
|
|
179
179
|
"max_concurrency",
|
|
180
180
|
"release_interval_ms",
|
|
181
|
-
"
|
|
181
|
+
"dequeue_prev_at",
|
|
182
182
|
"message_id",
|
|
183
183
|
"message_dequeue_at",
|
|
184
184
|
"message_seq_no"
|
|
@@ -194,8 +194,8 @@ var{defineProperty:h,getOwnPropertyNames:k,getOwnPropertyDescriptor:P}=Object,Q=
|
|
|
194
194
|
"message_id" = v_message."id",
|
|
195
195
|
"message_dequeue_at" = v_message."dequeue_at",
|
|
196
196
|
"message_seq_no" = v_message."seq_no",
|
|
197
|
-
"
|
|
198
|
-
v_channel_state."
|
|
197
|
+
"dequeue_next_at" = GREATEST(
|
|
198
|
+
v_channel_state."dequeue_prev_at" + INTERVAL '1 MILLISECOND' * COALESCE(v_channel_state."release_interval_ms", 0),
|
|
199
199
|
v_message."dequeue_at"
|
|
200
200
|
)
|
|
201
201
|
WHERE "id" = v_channel_state."id";
|
|
@@ -242,13 +242,13 @@ var{defineProperty:h,getOwnPropertyNames:k,getOwnPropertyDescriptor:P}=Object,Q=
|
|
|
242
242
|
"channel_state"."name",
|
|
243
243
|
"channel_state"."release_interval_ms",
|
|
244
244
|
"channel_state"."message_id",
|
|
245
|
-
"channel_state"."
|
|
246
|
-
"channel_state"."
|
|
245
|
+
"channel_state"."dequeue_next_at",
|
|
246
|
+
"channel_state"."dequeue_prev_at",
|
|
247
247
|
"channel_state"."current_concurrency"
|
|
248
248
|
FROM ${s(e.schema)}."channel_state"
|
|
249
249
|
WHERE "message_id" IS NOT NULL
|
|
250
250
|
AND ("max_concurrency" IS NULL OR "current_concurrency" < "max_concurrency")
|
|
251
|
-
ORDER BY "
|
|
251
|
+
ORDER BY "dequeue_next_at" ASC
|
|
252
252
|
`,_e=(e)=>n`
|
|
253
253
|
SELECT
|
|
254
254
|
"message"."id",
|
|
@@ -308,23 +308,12 @@ var{defineProperty:h,getOwnPropertyNames:k,getOwnPropertyDescriptor:P}=Object,Q=
|
|
|
308
308
|
LIMIT 1
|
|
309
309
|
INTO v_channel_state;
|
|
310
310
|
|
|
311
|
-
IF v_channel_state."id" IS NULL THEN
|
|
311
|
+
IF v_channel_state."id" IS NULL OR v_channel_state."dequeue_next_at" > v_now THEN
|
|
312
312
|
RETURN QUERY SELECT
|
|
313
313
|
${E(0)},
|
|
314
314
|
NULL::BYTEA,
|
|
315
315
|
NULL::BYTEA,
|
|
316
|
-
|
|
317
|
-
RETURN;
|
|
318
|
-
END IF;
|
|
319
|
-
|
|
320
|
-
IF v_channel_state."active_next_at" > v_now THEN
|
|
321
|
-
RETURN QUERY SELECT
|
|
322
|
-
${E(0)},
|
|
323
|
-
NULL::BYTEA,
|
|
324
|
-
NULL::BYTEA,
|
|
325
|
-
JSON_BUILD_OBJECT(
|
|
326
|
-
'retry_ms', CEIL(1_000 * EXTRACT(EPOCH FROM v_channel_state."active_next_at" - v_now))
|
|
327
|
-
);
|
|
316
|
+
NULL::JSON;
|
|
328
317
|
RETURN;
|
|
329
318
|
END IF;
|
|
330
319
|
|
|
@@ -351,7 +340,7 @@ var{defineProperty:h,getOwnPropertyNames:k,getOwnPropertyDescriptor:P}=Object,Q=
|
|
|
351
340
|
IF v_message_next."id" IS NULL THEN
|
|
352
341
|
UPDATE ${s(e.schema)}."channel_state" SET
|
|
353
342
|
"current_concurrency" = v_channel_state."current_concurrency" + 1,
|
|
354
|
-
"
|
|
343
|
+
"dequeue_prev_at" = v_now,
|
|
355
344
|
"message_id" = NULL
|
|
356
345
|
WHERE "id" = v_channel_state."id";
|
|
357
346
|
ELSE
|
|
@@ -360,8 +349,8 @@ var{defineProperty:h,getOwnPropertyNames:k,getOwnPropertyDescriptor:P}=Object,Q=
|
|
|
360
349
|
"message_id" = v_message_next."id",
|
|
361
350
|
"message_dequeue_at" = v_message_next."dequeue_at",
|
|
362
351
|
"message_seq_no" = v_message_next."seq_no",
|
|
363
|
-
"
|
|
364
|
-
"
|
|
352
|
+
"dequeue_prev_at" = v_now,
|
|
353
|
+
"dequeue_next_at" = GREATEST(
|
|
365
354
|
v_message_next."dequeue_at",
|
|
366
355
|
v_now + (COALESCE(v_channel_state."release_interval_ms", 0) * INTERVAL '1 millisecond')
|
|
367
356
|
)
|
|
@@ -370,13 +359,13 @@ var{defineProperty:h,getOwnPropertyNames:k,getOwnPropertyDescriptor:P}=Object,Q=
|
|
|
370
359
|
|
|
371
360
|
RETURN QUERY SELECT
|
|
372
361
|
${E(1)},
|
|
373
|
-
v_message_dequeue.content,
|
|
374
|
-
v_message_dequeue.state,
|
|
362
|
+
v_message_dequeue."content",
|
|
363
|
+
v_message_dequeue."state",
|
|
375
364
|
JSON_BUILD_OBJECT(
|
|
376
|
-
'id', v_message_dequeue.id,
|
|
365
|
+
'id', v_message_dequeue."id",
|
|
377
366
|
'is_unlocked', FALSE,
|
|
378
|
-
'channel_name', v_message_dequeue.channel_name,
|
|
379
|
-
'num_attempts', v_message_dequeue.num_attempts + 1
|
|
367
|
+
'channel_name', v_message_dequeue."channel_name",
|
|
368
|
+
'num_attempts', v_message_dequeue."num_attempts" + 1
|
|
380
369
|
);
|
|
381
370
|
RETURN;
|
|
382
371
|
END;
|
|
@@ -502,7 +491,7 @@ var{defineProperty:h,getOwnPropertyNames:k,getOwnPropertyDescriptor:P}=Object,Q=
|
|
|
502
491
|
"channel_state"."release_interval_ms",
|
|
503
492
|
"channel_state"."message_id",
|
|
504
493
|
"channel_state"."message_dequeue_at",
|
|
505
|
-
"channel_state"."
|
|
494
|
+
"channel_state"."dequeue_prev_at",
|
|
506
495
|
"channel_state"."message_seq_no"
|
|
507
496
|
FROM ${s(e.schema)}."channel_state"
|
|
508
497
|
WHERE "name" = v_message."channel_name"
|
|
@@ -521,8 +510,8 @@ var{defineProperty:h,getOwnPropertyNames:k,getOwnPropertyDescriptor:P}=Object,Q=
|
|
|
521
510
|
"message_id" = v_message."id",
|
|
522
511
|
"message_dequeue_at" = v_dequeue_at,
|
|
523
512
|
"message_seq_no" = v_message."seq_no",
|
|
524
|
-
"
|
|
525
|
-
v_channel_state."
|
|
513
|
+
"dequeue_next_at" = GREATEST(
|
|
514
|
+
v_channel_state."dequeue_prev_at" + INTERVAL '1 MILLISECOND' * COALESCE(v_channel_state."release_interval_ms", 0),
|
|
526
515
|
v_dequeue_at
|
|
527
516
|
)
|
|
528
517
|
WHERE "name" = v_message."channel_name";
|
|
@@ -614,7 +603,7 @@ var{defineProperty:h,getOwnPropertyNames:k,getOwnPropertyDescriptor:P}=Object,Q=
|
|
|
614
603
|
WHERE "name" = p_name;
|
|
615
604
|
END;
|
|
616
605
|
$$ LANGUAGE plpgsql;
|
|
617
|
-
`]}};class R{schema;channelName;adaptor;constructor(e){this.schema=e.schema,this.adaptor=e.adaptor,this.channelName=e.channelName}async create(e){let t=this.adaptor(e.databaseClient),a=new l({schema:this.schema,channelName:this.channelName,content:e.content,delayMs:e.delayMs}),r=await a.execute(t);return{messageId:r.
|
|
606
|
+
`]}};class R{schema;channelName;adaptor;constructor(e){this.schema=e.schema,this.adaptor=e.adaptor,this.channelName=e.channelName}async create(e){let t=this.adaptor(e.databaseClient),a=new l({schema:this.schema,channelName:this.channelName,content:e.content,delayMs:e.delayMs}),r=await a.execute(t);return{messageId:r.id,channelName:a.channelName,channelSize:r.channelSize}}}class A{schema;adaptor;channelName;constructor(e){this.schema=e.schema,this.adaptor=e.adaptor,this.channelName=e.channelName}set(e){let t=this.adaptor(e.databaseClient);return new c({schema:this.schema,channelName:this.channelName,maxConcurrency:e.maxConcurrency,releaseIntervalMs:e.releaseIntervalMs}).execute(t)}clear(e){let t=this.adaptor(e.databaseClient);return new o({schema:this.schema,channelName:this.channelName}).execute(t)}}class g{policy;message;constructor(e){this.message=new R({schema:e.schema,adaptor:e.adaptor,channelName:e.channelName}),this.policy=new A({schema:e.schema,adaptor:e.adaptor,channelName:e.channelName})}}class p{schema;adaptor;id;isUnlocked;channelName;content;state;numAttempts;constructor(e){this.schema=e.schema,this.adaptor=e.adaptor,this.id=e.id,this.channelName=e.channelName,this.isUnlocked=e.isUnlocked,this.content=e.content,this.state=e.state,this.numAttempts=e.numAttempts}async defer(e){let t=this.adaptor(e.databaseClient);return new i({schema:this.schema,id:this.id,numAttempts:this.numAttempts,delayMs:e.delayMs,state:e.state}).execute(t)}async delete(e){let t=this.adaptor(e.databaseClient);return new u({schema:this.schema,numAttempts:this.numAttempts,id:this.id}).execute(t)}async heartbeat(e){let t=this.adaptor(e.databaseClient);return new d({schema:this.schema,id:this.id,numAttempts:this.numAttempts,lockMs:e.lockMs}).execute(t)}}class D{schema;adaptor;constructor(e){this.schema=e.schema,this.adaptor=e.adaptor}async create(e){let t=this.adaptor(e.databaseClient),a=new l({schema:this.schema,content:e.content,delayMs:e.delayMs}),r=await a.execute(t);return{messageId:r.id,channelName:a.channelName,channelSize:r.channelSize}}}var __filename="/home/runner/work/lonnymq/lonnymq/src/install/07-function-message-heartbeat.ts",w={name:_(__filename),sql:(e)=>{return[n`
|
|
618
607
|
CREATE FUNCTION ${s(e.schema)}."message_heartbeat" (
|
|
619
608
|
p_id UUID,
|
|
620
609
|
p_num_attempts BIGINT,
|
|
@@ -664,4 +653,4 @@ var{defineProperty:h,getOwnPropertyNames:k,getOwnPropertyDescriptor:P}=Object,Q=
|
|
|
664
653
|
RETURN;
|
|
665
654
|
END;
|
|
666
655
|
$$ LANGUAGE plpgsql;
|
|
667
|
-
`]}};class y{schema;message;adaptor;constructor(e){this.schema=e.schema,this.adaptor=e.adaptor?e.adaptor:(t)=>t,this.message=new
|
|
656
|
+
`]}};class y{schema;message;adaptor;constructor(e){this.schema=e.schema,this.adaptor=e.adaptor?e.adaptor:(t)=>t,this.message=new D({schema:this.schema,adaptor:this.adaptor})}async dequeue(e){let t=new m({schema:this.schema,lockMs:e.lockMs}),a=this.adaptor(e.databaseClient),r=await t.execute(a);if(r.resultType==="MESSAGE_DEQUEUED")return{resultType:"MESSAGE_DEQUEUED",message:new p({schema:this.schema,adaptor:this.adaptor,id:r.id,channelName:r.channelName,isUnlocked:r.isUnlocked,content:r.content,state:r.state,numAttempts:r.numAttempts})};else return r}channel(e){return new g({adaptor:this.adaptor,schema:this.schema,channelName:e})}install(e={}){return[O,f,q,G,x,$,F,w,B,b].sort((t,a)=>t.name.localeCompare(a.name)).flatMap((t)=>t.sql({schema:this.schema,eventChannel:e.eventChannel??null})).map((t)=>U(t.value))}}
|
package/dist/index.d.ts
CHANGED
|
@@ -54,10 +54,8 @@ export declare class ChannelPolicySetCommand {
|
|
|
54
54
|
}
|
|
55
55
|
export type MessageCreateCommandResult = {
|
|
56
56
|
resultType: "MESSAGE_CREATED";
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
channelSize: number;
|
|
60
|
-
};
|
|
57
|
+
id: string;
|
|
58
|
+
channelSize: number;
|
|
61
59
|
};
|
|
62
60
|
export declare class MessageCreateCommand {
|
|
63
61
|
readonly schema: string;
|
|
@@ -75,18 +73,15 @@ export declare class MessageCreateCommand {
|
|
|
75
73
|
}
|
|
76
74
|
export type MessageDequeueCommandResultMessageDequeued = {
|
|
77
75
|
resultType: "MESSAGE_DEQUEUED";
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
numAttempts: number;
|
|
85
|
-
};
|
|
76
|
+
id: string;
|
|
77
|
+
channelName: string;
|
|
78
|
+
isUnlocked: boolean;
|
|
79
|
+
content: Buffer;
|
|
80
|
+
state: Buffer | null;
|
|
81
|
+
numAttempts: number;
|
|
86
82
|
};
|
|
87
83
|
export type MessageDequeueCommandResultMessageNotAvailable = {
|
|
88
84
|
resultType: "MESSAGE_NOT_AVAILABLE";
|
|
89
|
-
retryMs: number | null;
|
|
90
85
|
};
|
|
91
86
|
export type MessageDequeueCommandResult = MessageDequeueCommandResultMessageDequeued | MessageDequeueCommandResultMessageNotAvailable;
|
|
92
87
|
export declare class MessageDequeueCommand {
|
|
@@ -264,7 +259,6 @@ export declare class QueueMessageModule<T> {
|
|
|
264
259
|
}
|
|
265
260
|
export type MessageDequeueResult<T> = {
|
|
266
261
|
resultType: "MESSAGE_NOT_AVAILABLE";
|
|
267
|
-
retryMs: number | null;
|
|
268
262
|
} | {
|
|
269
263
|
resultType: "MESSAGE_DEQUEUED";
|
|
270
264
|
message: QueueMessage<T>;
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
var
|
|
1
|
+
var p=(e)=>{return e*1000};var o=p(0);var b=(e)=>{let t=JSON.parse(e);if(t.type===0)return{eventType:"MESSAGE_CREATED",id:t.id,delayMs:t.delay_ms};else if(t.type===1)return{eventType:"MESSAGE_DELETED",id:t.id};else if(t.type===2)return{eventType:"MESSAGE_DEFERRED",id:t.id,delayMs:t.delay_ms};else throw new Error("Unknown event type")};var E=(e)=>({nodeType:"VALUE",value:e}),s=(e)=>({nodeType:"REF",value:e}),B=(e)=>({nodeType:"RAW",value:e}),w=(e)=>{return`'${e.replace(/'/g,"''")}'`},H=(e)=>{if(e===null)return"NULL";else if(typeof e==="string")return w(e);else if(typeof e==="number")return e.toString();else if(typeof e==="boolean")return e?"TRUE":"FALSE";else if(e instanceof Date)return`'${e.toISOString()}'`;else if(typeof e==="bigint")return e.toString();else throw new Error(`Unsupported value type: ${typeof e}`)},k=(e)=>{return`"${e.replace(/"/g,'""')}"`},P=(e)=>{if(e.nodeType==="VALUE")return H(e.value);else if(e.nodeType==="REF")return k(e.value);else if(e.nodeType==="RAW")return e.value;else throw new Error("Unsupported SQL node type")};var n=(e,...t)=>{let a=[];for(let r=0;r<e.length;r+=1)if(a.push(e[r]),r<t.length)a.push(P(t[r]));return B(a.join(""))};class c{schema;channelName;createdAt;constructor(e){this.schema=e.schema,this.channelName=e.channelName,this.createdAt=new Date}async execute(e){await e.query(n`
|
|
2
2
|
SELECT 1 FROM ${s(this.schema)}."channel_policy_clear"(
|
|
3
3
|
$1
|
|
4
4
|
)
|
|
@@ -8,7 +8,7 @@ var D=(e)=>{return e*1000};var c=D(0);var b=(e)=>{let t=JSON.parse(e);if(t.type=
|
|
|
8
8
|
$2::INTEGER,
|
|
9
9
|
$3::INTEGER
|
|
10
10
|
)
|
|
11
|
-
`.value,[this.channelName,this.maxConcurrency,this.releaseIntervalMs])}}import{randomBytes as Q}from"crypto";var
|
|
11
|
+
`.value,[this.channelName,this.maxConcurrency,this.releaseIntervalMs])}}import{randomBytes as Q}from"crypto";var D=()=>{return Q(16).toString("base64url")};class l{schema;channelName;content;delayMs;createdAt;constructor(e){let t=e.delayMs===void 0?o:e.delayMs;this.schema=e.schema,this.channelName=e.channelName??D(),this.content=e.content,this.delayMs=t,this.createdAt=new Date}async execute(e){let t=await e.query(n`
|
|
12
12
|
SELECT
|
|
13
13
|
result_code,
|
|
14
14
|
metadata
|
|
@@ -17,19 +17,19 @@ var D=(e)=>{return e*1000};var c=D(0);var b=(e)=>{let t=JSON.parse(e);if(t.type=
|
|
|
17
17
|
$2,
|
|
18
18
|
$3::BIGINT
|
|
19
19
|
)
|
|
20
|
-
`.value,[this.channelName,this.content,this.delayMs]).then((a)=>a.rows[0]);if(t.result_code===0)return{resultType:"MESSAGE_CREATED",
|
|
20
|
+
`.value,[this.channelName,this.content,this.delayMs]).then((a)=>a.rows[0]);if(t.result_code===0)return{resultType:"MESSAGE_CREATED",id:t.metadata.id,channelSize:t.metadata.channel_size};else throw new Error("Unexpected result code")}}class u{schema;lockMs;constructor(e){this.schema=e.schema,this.lockMs=e.lockMs}async execute(e){let t=await e.query(n`
|
|
21
21
|
SELECT
|
|
22
22
|
result_code,
|
|
23
23
|
metadata,
|
|
24
24
|
content,
|
|
25
25
|
state
|
|
26
26
|
FROM ${s(this.schema)}."message_dequeue"($1::BIGINT)
|
|
27
|
-
`.value,[this.lockMs]).then((a)=>a.rows[0]);if(t.result_code===0)return{resultType:"MESSAGE_NOT_AVAILABLE"
|
|
27
|
+
`.value,[this.lockMs]).then((a)=>a.rows[0]);if(t.result_code===0)return{resultType:"MESSAGE_NOT_AVAILABLE"};else if(t.result_code===1)return{resultType:"MESSAGE_DEQUEUED",id:t.metadata.id,channelName:t.metadata.channel_name,isUnlocked:t.metadata.is_unlocked,content:t.content,state:t.state,numAttempts:t.metadata.num_attempts};else throw new Error("Unexpected dequeue result")}}class i{schema;id;numAttempts;constructor(e){this.schema=e.schema,this.id=e.id,this.numAttempts=e.numAttempts}async execute(e){let t=await e.query(n`
|
|
28
28
|
SELECT * FROM ${s(this.schema)}."message_delete"(
|
|
29
29
|
$1,
|
|
30
30
|
$2::BIGINT
|
|
31
31
|
)
|
|
32
|
-
`.value,[this.id,this.numAttempts]).then((a)=>a.rows[0]);if(t.result_code===0)return{resultType:"MESSAGE_NOT_FOUND"};else if(t.result_code===1)return{resultType:"STATE_INVALID"};else if(t.result_code===2)return{resultType:"MESSAGE_DELETED"};else throw new Error("Unexpected result")}}class d{schema;id;numAttempts;delayMs;state;constructor(e){let t=e.delayMs===void 0?
|
|
32
|
+
`.value,[this.id,this.numAttempts]).then((a)=>a.rows[0]);if(t.result_code===0)return{resultType:"MESSAGE_NOT_FOUND"};else if(t.result_code===1)return{resultType:"STATE_INVALID"};else if(t.result_code===2)return{resultType:"MESSAGE_DELETED"};else throw new Error("Unexpected result")}}class d{schema;id;numAttempts;delayMs;state;constructor(e){let t=e.delayMs===void 0?o:e.delayMs;this.schema=e.schema,this.numAttempts=e.numAttempts,this.id=e.id,this.delayMs=t,this.state=e.state??null}async execute(e){let t=await e.query(n`
|
|
33
33
|
SELECT * FROM ${s(this.schema)}."message_defer"(
|
|
34
34
|
$1,
|
|
35
35
|
$2::BIGINT,
|
|
@@ -43,8 +43,8 @@ var D=(e)=>{return e*1000};var c=D(0);var b=(e)=>{let t=JSON.parse(e);if(t.type=
|
|
|
43
43
|
$3::BIGINT
|
|
44
44
|
)
|
|
45
45
|
`.value,[this.id,this.numAttempts,this.lockMs]).then((a)=>a.rows[0]);if(t.result_code===0)return{resultType:"MESSAGE_NOT_FOUND"};else if(t.result_code===1)return{resultType:"MESSAGE_STATE_INVALID"};else if(t.result_code===2)return{resultType:"MESSAGE_HEARTBEATED"};else throw new Error("Unexpected result")}}var y=(e)=>{let t=e.split(`
|
|
46
|
-
`),a=Number.MAX_SAFE_INTEGER;for(let
|
|
47
|
-
`).trim()};import{dirname as M}from"path";var __filename="/home/runner/work/lonnymq/lonnymq/src/core/path.ts",
|
|
46
|
+
`),a=Number.MAX_SAFE_INTEGER;for(let r of t){if(r.trim().length===0)continue;let F=r.search(/\S/);a=Math.min(a,F)}return t.map((r)=>r.slice(a)).join(`
|
|
47
|
+
`).trim()};import{dirname as M}from"path";var __filename="/home/runner/work/lonnymq/lonnymq/src/core/path.ts",J=M(M(__filename)),j=new RegExp(`^${J}/`),_=(e)=>{return e.replace(j,"")};var __filename="/home/runner/work/lonnymq/lonnymq/src/install/00-table-channel-policy.ts",I={name:_(__filename),sql:(e)=>{let t=[e.schema,"channel_policy_name_ux"].join("_");return[n`
|
|
48
48
|
CREATE TABLE ${s(e.schema)}."channel_policy" (
|
|
49
49
|
"id" UUID NOT NULL DEFAULT GEN_RANDOM_UUID(),
|
|
50
50
|
"name" TEXT NOT NULL,
|
|
@@ -67,8 +67,8 @@ var D=(e)=>{return e*1000};var c=D(0);var b=(e)=>{let t=JSON.parse(e);if(t.type=
|
|
|
67
67
|
"message_id" UUID,
|
|
68
68
|
"message_seq_no" BIGINT,
|
|
69
69
|
"message_dequeue_at" TIMESTAMP,
|
|
70
|
-
"
|
|
71
|
-
"
|
|
70
|
+
"dequeue_prev_at" TIMESTAMP NOT NULL,
|
|
71
|
+
"dequeue_next_at" TIMESTAMP NULL,
|
|
72
72
|
"created_at" TIMESTAMP NOT NULL,
|
|
73
73
|
PRIMARY KEY ("id")
|
|
74
74
|
);
|
|
@@ -78,7 +78,7 @@ var D=(e)=>{return e*1000};var c=D(0);var b=(e)=>{let t=JSON.parse(e);if(t.type=
|
|
|
78
78
|
`,n`
|
|
79
79
|
CREATE INDEX ${s(a)}
|
|
80
80
|
ON ${s(e.schema)}."channel_state" (
|
|
81
|
-
"
|
|
81
|
+
"dequeue_next_at" ASC
|
|
82
82
|
) WHERE "message_id" IS NOT NULL
|
|
83
83
|
AND ("max_concurrency" IS NULL OR "current_concurrency" < "max_concurrency");
|
|
84
84
|
`]}};var __filename="/home/runner/work/lonnymq/lonnymq/src/install/02-table-message.ts",L={name:_(__filename),sql:(e)=>{return[n`
|
|
@@ -160,7 +160,7 @@ var D=(e)=>{return e*1000};var c=D(0);var b=(e)=>{let t=JSON.parse(e);if(t.type=
|
|
|
160
160
|
"current_size",
|
|
161
161
|
"max_concurrency",
|
|
162
162
|
"release_interval_ms",
|
|
163
|
-
"
|
|
163
|
+
"dequeue_prev_at",
|
|
164
164
|
"created_at"
|
|
165
165
|
) VALUES (
|
|
166
166
|
p_channel_name,
|
|
@@ -178,7 +178,7 @@ var D=(e)=>{return e*1000};var c=D(0);var b=(e)=>{let t=JSON.parse(e);if(t.type=
|
|
|
178
178
|
"current_size",
|
|
179
179
|
"max_concurrency",
|
|
180
180
|
"release_interval_ms",
|
|
181
|
-
"
|
|
181
|
+
"dequeue_prev_at",
|
|
182
182
|
"message_id",
|
|
183
183
|
"message_dequeue_at",
|
|
184
184
|
"message_seq_no"
|
|
@@ -194,8 +194,8 @@ var D=(e)=>{return e*1000};var c=D(0);var b=(e)=>{let t=JSON.parse(e);if(t.type=
|
|
|
194
194
|
"message_id" = v_message."id",
|
|
195
195
|
"message_dequeue_at" = v_message."dequeue_at",
|
|
196
196
|
"message_seq_no" = v_message."seq_no",
|
|
197
|
-
"
|
|
198
|
-
v_channel_state."
|
|
197
|
+
"dequeue_next_at" = GREATEST(
|
|
198
|
+
v_channel_state."dequeue_prev_at" + INTERVAL '1 MILLISECOND' * COALESCE(v_channel_state."release_interval_ms", 0),
|
|
199
199
|
v_message."dequeue_at"
|
|
200
200
|
)
|
|
201
201
|
WHERE "id" = v_channel_state."id";
|
|
@@ -205,11 +205,11 @@ var D=(e)=>{return e*1000};var c=D(0);var b=(e)=>{let t=JSON.parse(e);if(t.type=
|
|
|
205
205
|
WHERE "id" = v_channel_state."id";
|
|
206
206
|
END IF;
|
|
207
207
|
|
|
208
|
-
IF ${
|
|
208
|
+
IF ${E(e.eventChannel!==null)} THEN
|
|
209
209
|
PERFORM PG_NOTIFY(
|
|
210
|
-
${
|
|
210
|
+
${E(e.eventChannel)},
|
|
211
211
|
JSON_BUILD_OBJECT(
|
|
212
|
-
'type', ${
|
|
212
|
+
'type', ${E(0)},
|
|
213
213
|
'id', v_message."id",
|
|
214
214
|
'delay_ms', p_delay_ms
|
|
215
215
|
)::TEXT
|
|
@@ -217,7 +217,7 @@ var D=(e)=>{return e*1000};var c=D(0);var b=(e)=>{let t=JSON.parse(e);if(t.type=
|
|
|
217
217
|
END IF;
|
|
218
218
|
|
|
219
219
|
RETURN QUERY SELECT
|
|
220
|
-
${
|
|
220
|
+
${E(0)},
|
|
221
221
|
JSON_BUILD_OBJECT(
|
|
222
222
|
'id', v_message."id",
|
|
223
223
|
'channel_size', v_channel_state."current_size" + 1
|
|
@@ -242,13 +242,13 @@ var D=(e)=>{return e*1000};var c=D(0);var b=(e)=>{let t=JSON.parse(e);if(t.type=
|
|
|
242
242
|
"channel_state"."name",
|
|
243
243
|
"channel_state"."release_interval_ms",
|
|
244
244
|
"channel_state"."message_id",
|
|
245
|
-
"channel_state"."
|
|
246
|
-
"channel_state"."
|
|
245
|
+
"channel_state"."dequeue_next_at",
|
|
246
|
+
"channel_state"."dequeue_prev_at",
|
|
247
247
|
"channel_state"."current_concurrency"
|
|
248
248
|
FROM ${s(e.schema)}."channel_state"
|
|
249
249
|
WHERE "message_id" IS NOT NULL
|
|
250
250
|
AND ("max_concurrency" IS NULL OR "current_concurrency" < "max_concurrency")
|
|
251
|
-
ORDER BY "
|
|
251
|
+
ORDER BY "dequeue_next_at" ASC
|
|
252
252
|
`,ee=(e)=>n`
|
|
253
253
|
SELECT
|
|
254
254
|
"message"."id",
|
|
@@ -258,7 +258,7 @@ var D=(e)=>{return e*1000};var c=D(0);var b=(e)=>{let t=JSON.parse(e);if(t.type=
|
|
|
258
258
|
WHERE NOT "is_locked"
|
|
259
259
|
AND "channel_name" = ${e.channelName}
|
|
260
260
|
ORDER BY "dequeue_at" ASC, "seq_no" ASC
|
|
261
|
-
`,U={name:_(__filename),sql:(e)=>{let t=K({now:n`v_now`,schema:e.schema}),a=ee({channelName:n`v_channel_state."name"`,schema:e.schema}),
|
|
261
|
+
`,U={name:_(__filename),sql:(e)=>{let t=K({now:n`v_now`,schema:e.schema}),a=ee({channelName:n`v_channel_state."name"`,schema:e.schema}),r=Z({schema:e.schema});return[n`
|
|
262
262
|
CREATE FUNCTION ${s(e.schema)}."message_dequeue" (
|
|
263
263
|
p_lock_ms BIGINT
|
|
264
264
|
)
|
|
@@ -290,7 +290,7 @@ var D=(e)=>{return e*1000};var c=D(0);var b=(e)=>{let t=JSON.parse(e);if(t.type=
|
|
|
290
290
|
WHERE "id" = v_message_locked."id";
|
|
291
291
|
|
|
292
292
|
RETURN QUERY SELECT
|
|
293
|
-
${
|
|
293
|
+
${E(1)},
|
|
294
294
|
v_message_locked.content,
|
|
295
295
|
v_message_locked.state,
|
|
296
296
|
JSON_BUILD_OBJECT(
|
|
@@ -302,29 +302,18 @@ var D=(e)=>{return e*1000};var c=D(0);var b=(e)=>{let t=JSON.parse(e);if(t.type=
|
|
|
302
302
|
RETURN;
|
|
303
303
|
END IF;
|
|
304
304
|
|
|
305
|
-
${
|
|
305
|
+
${r}
|
|
306
306
|
FOR UPDATE
|
|
307
307
|
SKIP LOCKED
|
|
308
308
|
LIMIT 1
|
|
309
309
|
INTO v_channel_state;
|
|
310
310
|
|
|
311
|
-
IF v_channel_state."id" IS NULL THEN
|
|
311
|
+
IF v_channel_state."id" IS NULL OR v_channel_state."dequeue_next_at" > v_now THEN
|
|
312
312
|
RETURN QUERY SELECT
|
|
313
|
-
${
|
|
313
|
+
${E(0)},
|
|
314
314
|
NULL::BYTEA,
|
|
315
315
|
NULL::BYTEA,
|
|
316
|
-
|
|
317
|
-
RETURN;
|
|
318
|
-
END IF;
|
|
319
|
-
|
|
320
|
-
IF v_channel_state."active_next_at" > v_now THEN
|
|
321
|
-
RETURN QUERY SELECT
|
|
322
|
-
${r(0)},
|
|
323
|
-
NULL::BYTEA,
|
|
324
|
-
NULL::BYTEA,
|
|
325
|
-
JSON_BUILD_OBJECT(
|
|
326
|
-
'retry_ms', CEIL(1_000 * EXTRACT(EPOCH FROM v_channel_state."active_next_at" - v_now))
|
|
327
|
-
);
|
|
316
|
+
NULL::JSON;
|
|
328
317
|
RETURN;
|
|
329
318
|
END IF;
|
|
330
319
|
|
|
@@ -351,7 +340,7 @@ var D=(e)=>{return e*1000};var c=D(0);var b=(e)=>{let t=JSON.parse(e);if(t.type=
|
|
|
351
340
|
IF v_message_next."id" IS NULL THEN
|
|
352
341
|
UPDATE ${s(e.schema)}."channel_state" SET
|
|
353
342
|
"current_concurrency" = v_channel_state."current_concurrency" + 1,
|
|
354
|
-
"
|
|
343
|
+
"dequeue_prev_at" = v_now,
|
|
355
344
|
"message_id" = NULL
|
|
356
345
|
WHERE "id" = v_channel_state."id";
|
|
357
346
|
ELSE
|
|
@@ -360,8 +349,8 @@ var D=(e)=>{return e*1000};var c=D(0);var b=(e)=>{let t=JSON.parse(e);if(t.type=
|
|
|
360
349
|
"message_id" = v_message_next."id",
|
|
361
350
|
"message_dequeue_at" = v_message_next."dequeue_at",
|
|
362
351
|
"message_seq_no" = v_message_next."seq_no",
|
|
363
|
-
"
|
|
364
|
-
"
|
|
352
|
+
"dequeue_prev_at" = v_now,
|
|
353
|
+
"dequeue_next_at" = GREATEST(
|
|
365
354
|
v_message_next."dequeue_at",
|
|
366
355
|
v_now + (COALESCE(v_channel_state."release_interval_ms", 0) * INTERVAL '1 millisecond')
|
|
367
356
|
)
|
|
@@ -369,14 +358,14 @@ var D=(e)=>{return e*1000};var c=D(0);var b=(e)=>{let t=JSON.parse(e);if(t.type=
|
|
|
369
358
|
END IF;
|
|
370
359
|
|
|
371
360
|
RETURN QUERY SELECT
|
|
372
|
-
${
|
|
373
|
-
v_message_dequeue.content,
|
|
374
|
-
v_message_dequeue.state,
|
|
361
|
+
${E(1)},
|
|
362
|
+
v_message_dequeue."content",
|
|
363
|
+
v_message_dequeue."state",
|
|
375
364
|
JSON_BUILD_OBJECT(
|
|
376
|
-
'id', v_message_dequeue.id,
|
|
365
|
+
'id', v_message_dequeue."id",
|
|
377
366
|
'is_unlocked', FALSE,
|
|
378
|
-
'channel_name', v_message_dequeue.channel_name,
|
|
379
|
-
'num_attempts', v_message_dequeue.num_attempts + 1
|
|
367
|
+
'channel_name', v_message_dequeue."channel_name",
|
|
368
|
+
'num_attempts', v_message_dequeue."num_attempts" + 1
|
|
380
369
|
);
|
|
381
370
|
RETURN;
|
|
382
371
|
END;
|
|
@@ -406,11 +395,11 @@ var D=(e)=>{return e*1000};var c=D(0);var b=(e)=>{let t=JSON.parse(e);if(t.type=
|
|
|
406
395
|
|
|
407
396
|
IF v_message."id" IS NULL THEN
|
|
408
397
|
RETURN QUERY SELECT
|
|
409
|
-
${
|
|
398
|
+
${E(0)};
|
|
410
399
|
RETURN;
|
|
411
400
|
ELSIF NOT v_message."is_locked" OR v_message."num_attempts" <> p_num_attempts THEN
|
|
412
401
|
RETURN QUERY SELECT
|
|
413
|
-
${
|
|
402
|
+
${E(1)};
|
|
414
403
|
RETURN;
|
|
415
404
|
END IF;
|
|
416
405
|
|
|
@@ -440,11 +429,11 @@ var D=(e)=>{return e*1000};var c=D(0);var b=(e)=>{let t=JSON.parse(e);if(t.type=
|
|
|
440
429
|
WHERE "id" = v_channel_state."id";
|
|
441
430
|
END IF;
|
|
442
431
|
|
|
443
|
-
IF ${
|
|
432
|
+
IF ${E(e.eventChannel!==null)} THEN
|
|
444
433
|
PERFORM PG_NOTIFY(
|
|
445
|
-
${
|
|
434
|
+
${E(e.eventChannel)},
|
|
446
435
|
JSON_BUILD_OBJECT(
|
|
447
|
-
'type', ${
|
|
436
|
+
'type', ${E(1)},
|
|
448
437
|
'id', p_id
|
|
449
438
|
)::TEXT
|
|
450
439
|
);
|
|
@@ -454,7 +443,7 @@ var D=(e)=>{return e*1000};var c=D(0);var b=(e)=>{let t=JSON.parse(e);if(t.type=
|
|
|
454
443
|
WHERE "id" = p_id;
|
|
455
444
|
|
|
456
445
|
RETURN QUERY SELECT
|
|
457
|
-
${
|
|
446
|
+
${E(2)};
|
|
458
447
|
RETURN;
|
|
459
448
|
END;
|
|
460
449
|
$$ LANGUAGE plpgsql;
|
|
@@ -489,11 +478,11 @@ var D=(e)=>{return e*1000};var c=D(0);var b=(e)=>{let t=JSON.parse(e);if(t.type=
|
|
|
489
478
|
|
|
490
479
|
IF v_message."id" IS NULL THEN
|
|
491
480
|
RETURN QUERY SELECT
|
|
492
|
-
${
|
|
481
|
+
${E(0)};
|
|
493
482
|
RETURN;
|
|
494
483
|
ELSIF NOT v_message."is_locked" OR v_message."num_attempts" <> p_num_attempts THEN
|
|
495
484
|
RETURN QUERY SELECT
|
|
496
|
-
${
|
|
485
|
+
${E(1)};
|
|
497
486
|
RETURN;
|
|
498
487
|
END IF;
|
|
499
488
|
|
|
@@ -502,7 +491,7 @@ var D=(e)=>{return e*1000};var c=D(0);var b=(e)=>{let t=JSON.parse(e);if(t.type=
|
|
|
502
491
|
"channel_state"."release_interval_ms",
|
|
503
492
|
"channel_state"."message_id",
|
|
504
493
|
"channel_state"."message_dequeue_at",
|
|
505
|
-
"channel_state"."
|
|
494
|
+
"channel_state"."dequeue_prev_at",
|
|
506
495
|
"channel_state"."message_seq_no"
|
|
507
496
|
FROM ${s(e.schema)}."channel_state"
|
|
508
497
|
WHERE "name" = v_message."channel_name"
|
|
@@ -521,8 +510,8 @@ var D=(e)=>{return e*1000};var c=D(0);var b=(e)=>{let t=JSON.parse(e);if(t.type=
|
|
|
521
510
|
"message_id" = v_message."id",
|
|
522
511
|
"message_dequeue_at" = v_dequeue_at,
|
|
523
512
|
"message_seq_no" = v_message."seq_no",
|
|
524
|
-
"
|
|
525
|
-
v_channel_state."
|
|
513
|
+
"dequeue_next_at" = GREATEST(
|
|
514
|
+
v_channel_state."dequeue_prev_at" + INTERVAL '1 MILLISECOND' * COALESCE(v_channel_state."release_interval_ms", 0),
|
|
526
515
|
v_dequeue_at
|
|
527
516
|
)
|
|
528
517
|
WHERE "name" = v_message."channel_name";
|
|
@@ -538,11 +527,11 @@ var D=(e)=>{return e*1000};var c=D(0);var b=(e)=>{let t=JSON.parse(e);if(t.type=
|
|
|
538
527
|
"dequeue_at" = v_dequeue_at
|
|
539
528
|
WHERE "id" = p_id;
|
|
540
529
|
|
|
541
|
-
IF ${
|
|
530
|
+
IF ${E(e.eventChannel!==null)} THEN
|
|
542
531
|
PERFORM PG_NOTIFY(
|
|
543
|
-
${
|
|
532
|
+
${E(e.eventChannel)},
|
|
544
533
|
JSON_BUILD_OBJECT(
|
|
545
|
-
'type', ${
|
|
534
|
+
'type', ${E(2)},
|
|
546
535
|
'delay_ms', p_delay_ms,
|
|
547
536
|
'id', p_id
|
|
548
537
|
)::TEXT
|
|
@@ -550,11 +539,11 @@ var D=(e)=>{return e*1000};var c=D(0);var b=(e)=>{let t=JSON.parse(e);if(t.type=
|
|
|
550
539
|
END IF;
|
|
551
540
|
|
|
552
541
|
RETURN QUERY SELECT
|
|
553
|
-
${
|
|
542
|
+
${E(2)};
|
|
554
543
|
RETURN;
|
|
555
544
|
END;
|
|
556
545
|
$$ LANGUAGE plpgsql;
|
|
557
|
-
`]}};var __filename="/home/runner/work/lonnymq/lonnymq/src/install/08-function-channel-policy-clear.ts",
|
|
546
|
+
`]}};var __filename="/home/runner/work/lonnymq/lonnymq/src/install/08-function-channel-policy-clear.ts",q={name:_(__filename),sql:(e)=>{return[n`
|
|
558
547
|
CREATE FUNCTION ${s(e.schema)}."channel_policy_clear" (
|
|
559
548
|
p_name TEXT
|
|
560
549
|
) RETURNS VOID AS $$
|
|
@@ -583,7 +572,7 @@ var D=(e)=>{return e*1000};var c=D(0);var b=(e)=>{let t=JSON.parse(e);if(t.type=
|
|
|
583
572
|
END IF;
|
|
584
573
|
END;
|
|
585
574
|
$$ LANGUAGE plpgsql;
|
|
586
|
-
`]}};var __filename="/home/runner/work/lonnymq/lonnymq/src/install/09-function-channel-policy-set.ts",
|
|
575
|
+
`]}};var __filename="/home/runner/work/lonnymq/lonnymq/src/install/09-function-channel-policy-set.ts",G={name:_(__filename),sql:(e)=>{return[n`
|
|
587
576
|
CREATE FUNCTION ${s(e.schema)}."channel_policy_set" (
|
|
588
577
|
p_name TEXT,
|
|
589
578
|
p_max_concurrency INTEGER,
|
|
@@ -614,7 +603,7 @@ var D=(e)=>{return e*1000};var c=D(0);var b=(e)=>{let t=JSON.parse(e);if(t.type=
|
|
|
614
603
|
WHERE "name" = p_name;
|
|
615
604
|
END;
|
|
616
605
|
$$ LANGUAGE plpgsql;
|
|
617
|
-
`]}};class N{schema;channelName;adaptor;constructor(e){this.schema=e.schema,this.adaptor=e.adaptor,this.channelName=e.channelName}async create(e){let t=this.adaptor(e.databaseClient),a=new l({schema:this.schema,channelName:this.channelName,content:e.content,delayMs:e.delayMs}),
|
|
606
|
+
`]}};class N{schema;channelName;adaptor;constructor(e){this.schema=e.schema,this.adaptor=e.adaptor,this.channelName=e.channelName}async create(e){let t=this.adaptor(e.databaseClient),a=new l({schema:this.schema,channelName:this.channelName,content:e.content,delayMs:e.delayMs}),r=await a.execute(t);return{messageId:r.id,channelName:a.channelName,channelSize:r.channelSize}}}class S{schema;adaptor;channelName;constructor(e){this.schema=e.schema,this.adaptor=e.adaptor,this.channelName=e.channelName}set(e){let t=this.adaptor(e.databaseClient);return new m({schema:this.schema,channelName:this.channelName,maxConcurrency:e.maxConcurrency,releaseIntervalMs:e.releaseIntervalMs}).execute(t)}clear(e){let t=this.adaptor(e.databaseClient);return new c({schema:this.schema,channelName:this.channelName}).execute(t)}}class R{policy;message;constructor(e){this.message=new N({schema:e.schema,adaptor:e.adaptor,channelName:e.channelName}),this.policy=new S({schema:e.schema,adaptor:e.adaptor,channelName:e.channelName})}}class A{schema;adaptor;id;isUnlocked;channelName;content;state;numAttempts;constructor(e){this.schema=e.schema,this.adaptor=e.adaptor,this.id=e.id,this.channelName=e.channelName,this.isUnlocked=e.isUnlocked,this.content=e.content,this.state=e.state,this.numAttempts=e.numAttempts}async defer(e){let t=this.adaptor(e.databaseClient);return new d({schema:this.schema,id:this.id,numAttempts:this.numAttempts,delayMs:e.delayMs,state:e.state}).execute(t)}async delete(e){let t=this.adaptor(e.databaseClient);return new i({schema:this.schema,numAttempts:this.numAttempts,id:this.id}).execute(t)}async heartbeat(e){let t=this.adaptor(e.databaseClient);return new T({schema:this.schema,id:this.id,numAttempts:this.numAttempts,lockMs:e.lockMs}).execute(t)}}class g{schema;adaptor;constructor(e){this.schema=e.schema,this.adaptor=e.adaptor}async create(e){let t=this.adaptor(e.databaseClient),a=new l({schema:this.schema,content:e.content,delayMs:e.delayMs}),r=await a.execute(t);return{messageId:r.id,channelName:a.channelName,channelSize:r.channelSize}}}var __filename="/home/runner/work/lonnymq/lonnymq/src/install/07-function-message-heartbeat.ts",x={name:_(__filename),sql:(e)=>{return[n`
|
|
618
607
|
CREATE FUNCTION ${s(e.schema)}."message_heartbeat" (
|
|
619
608
|
p_id UUID,
|
|
620
609
|
p_num_attempts BIGINT,
|
|
@@ -644,11 +633,11 @@ var D=(e)=>{return e*1000};var c=D(0);var b=(e)=>{let t=JSON.parse(e);if(t.type=
|
|
|
644
633
|
|
|
645
634
|
IF v_message."id" IS NULL THEN
|
|
646
635
|
RETURN QUERY SELECT
|
|
647
|
-
${
|
|
636
|
+
${E(0)};
|
|
648
637
|
RETURN;
|
|
649
638
|
ELSIF NOT v_message."is_locked" OR v_message."num_attempts" <> p_num_attempts THEN
|
|
650
639
|
RETURN QUERY SELECT
|
|
651
|
-
${
|
|
640
|
+
${E(1)};
|
|
652
641
|
RETURN;
|
|
653
642
|
END IF;
|
|
654
643
|
|
|
@@ -660,8 +649,8 @@ var D=(e)=>{return e*1000};var c=D(0);var b=(e)=>{let t=JSON.parse(e);if(t.type=
|
|
|
660
649
|
WHERE "id" = p_id;
|
|
661
650
|
|
|
662
651
|
RETURN QUERY SELECT
|
|
663
|
-
${
|
|
652
|
+
${E(2)};
|
|
664
653
|
RETURN;
|
|
665
654
|
END;
|
|
666
655
|
$$ LANGUAGE plpgsql;
|
|
667
|
-
`]}};class ${schema;message;adaptor;constructor(e){this.schema=e.schema,this.adaptor=e.adaptor?e.adaptor:(t)=>t,this.message=new g({schema:this.schema,adaptor:this.adaptor})}async dequeue(e){let t=new
|
|
656
|
+
`]}};class ${schema;message;adaptor;constructor(e){this.schema=e.schema,this.adaptor=e.adaptor?e.adaptor:(t)=>t,this.message=new g({schema:this.schema,adaptor:this.adaptor})}async dequeue(e){let t=new u({schema:this.schema,lockMs:e.lockMs}),a=this.adaptor(e.databaseClient),r=await t.execute(a);if(r.resultType==="MESSAGE_DEQUEUED")return{resultType:"MESSAGE_DEQUEUED",message:new A({schema:this.schema,adaptor:this.adaptor,id:r.id,channelName:r.channelName,isUnlocked:r.isUnlocked,content:r.content,state:r.state,numAttempts:r.numAttempts})};else return r}channel(e){return new R({adaptor:this.adaptor,schema:this.schema,channelName:e})}install(e={}){return[I,v,L,C,U,O,f,x,G,q].sort((t,a)=>t.name.localeCompare(a.name)).flatMap((t)=>t.sql({schema:this.schema,eventChannel:e.eventChannel??null})).map((t)=>y(t.value))}}export{b as queueEventDecode,$ as Queue,T as MessageHeartbeatCommand,u as MessageDequeueCommand,i as MessageDeleteCommand,d as MessageDeferCommand,l as MessageCreateCommand,m as ChannelPolicySetCommand,c as ChannelPolicyClearCommand};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "lonnymq",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.28",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"exports": {
|
|
6
6
|
".": {
|
|
@@ -18,7 +18,8 @@
|
|
|
18
18
|
"@typescript-eslint/parser": "8.26.1",
|
|
19
19
|
"bun-plugin-dts": "^0.3.0",
|
|
20
20
|
"eslint": "9.22.0",
|
|
21
|
-
"pg": "^8.16.3"
|
|
21
|
+
"pg": "^8.16.3",
|
|
22
|
+
"typedoc": "^0.28.13"
|
|
22
23
|
},
|
|
23
24
|
"peerDependencies": {
|
|
24
25
|
"typescript": "^5.0.0"
|