lonnymq 0.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.
- package/README.md +180 -0
- package/dist/index.cjs +531 -0
- package/dist/index.d.ts +304 -0
- package/dist/index.js +531 -0
- package/package.json +27 -0
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,531 @@
|
|
|
1
|
+
var{defineProperty:g,getOwnPropertyNames:K,getOwnPropertyDescriptor:Q}=Object,Y=Object.prototype.hasOwnProperty;var q=new WeakMap,j=(e)=>{var n=q.get(e),_;if(n)return n;if(n=g({},"__esModule",{value:!0}),e&&typeof e==="object"||typeof e==="function")K(e).map((c)=>!Y.call(n,c)&&g(n,c,{get:()=>e[c],enumerable:!(_=Q(e,c))||_.enumerable}));return q.set(e,n),n};var Z=(e,n)=>{for(var _ in n)g(e,_,{get:n[_],enumerable:!0,configurable:!0,set:(c)=>n[_]=()=>c})};var oe={};Z(oe,{Queue:()=>p,MessageDequeueCommand:()=>l,MessageDeleteCommand:()=>d,MessageDeferCommand:()=>h,MessageCreateCommand:()=>i,ChannelPolicySetCommand:()=>o,ChannelPolicyClearCommand:()=>E});module.exports=j(oe);var s=(e)=>({nodeType:"VALUE",value:e}),t=(e)=>({nodeType:"REF",value:e}),ee=(e)=>({nodeType:"RAW",value:e}),ne=(e)=>{return`'${e.replace(/'/g,"''")}'`},te=(e)=>{if(e===null)return"NULL";else if(typeof e==="string")return ne(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 throw new Error(`Unsupported value type: ${typeof e}`)},_e=(e)=>{return`"${e.replace(/"/g,'""')}"`},se=(e)=>{if(e.nodeType==="VALUE")return te(e.value);else if(e.nodeType==="REF")return _e(e.value);else if(e.nodeType==="RAW")return e.value;else throw new Error("Unsupported SQL node type")};var a=(e,...n)=>{let _=[];for(let c=0;c<e.length;c+=1)if(_.push(e[c]),c<n.length)_.push(se(n[c]));return ee(_.join(""))};class E{schema;channelName;createdAt;constructor(e){this.schema=e.schema,this.channelName=e.channelName,this.createdAt=new Date}sortKeyGet(){return JSON.stringify([this.channelName,null,this.createdAt.toISOString()])}async execute(e){await e.query(a`
|
|
2
|
+
SELECT 1 FROM ${t(this.schema)}."channel_policy_clear"(
|
|
3
|
+
${s(this.channelName)}
|
|
4
|
+
)
|
|
5
|
+
`.value)}}class o{schema;channelName;maxSize;maxConcurrency;createdAt;constructor(e){this.schema=e.schema,this.channelName=e.channelName,this.maxConcurrency=e.maxConcurrency===null?null:Math.max(0,e.maxConcurrency),this.maxSize=e.maxSize===null?null:Math.max(0,e.maxSize),this.createdAt=new Date}sortKeyGet(){return JSON.stringify([this.channelName,null,this.createdAt.toISOString()])}async execute(e){await e.query(a`
|
|
6
|
+
SELECT 1 FROM ${t(this.schema)}."channel_policy_set"(
|
|
7
|
+
${s(this.channelName)},
|
|
8
|
+
${s(this.maxSize)}::BIGINT,
|
|
9
|
+
${s(this.maxConcurrency)}::BIGINT
|
|
10
|
+
)
|
|
11
|
+
`.value)}}var R=(e)=>{return e*1000},ae=(e)=>{return R(e*60)},I=(e)=>{return ae(e*60)},C=(e)=>{return I(e*24)};var $=require("node:crypto");class F{value;constructor(e){this.value=e}toString(e){return $.createHash("sha256").update(e).update(this.value).digest("base64").replace(/=/g,"")}}var N=new F("WAKE"),T=C(1000),M=!1,S=R(0),B=I(1);var A=require("path"),__filename="/home/runner/work/lonnymq/lonnymq/src/core/path.ts",ce=A.dirname(A.dirname(__filename)),re=new RegExp(`^${ce}/`),r=(e)=>{return e.replace(re,"")};var __filename="/home/runner/work/lonnymq/lonnymq/src/migration/04-function-message-create.ts";var G={name:r(__filename),sql:(e)=>{return[a`
|
|
12
|
+
CREATE FUNCTION ${t(e.schema)}."message_create" (
|
|
13
|
+
p_channel_name TEXT,
|
|
14
|
+
p_name TEXT,
|
|
15
|
+
p_content TEXT,
|
|
16
|
+
p_lock_ms BIGINT,
|
|
17
|
+
p_delay_ms BIGINT
|
|
18
|
+
) RETURNS JSONB AS $$
|
|
19
|
+
DECLARE
|
|
20
|
+
v_now TIMESTAMP;
|
|
21
|
+
v_channel_policy RECORD;
|
|
22
|
+
v_channel_state RECORD;
|
|
23
|
+
v_message RECORD;
|
|
24
|
+
v_message_next_dequeue_after TIMESTAMP;
|
|
25
|
+
BEGIN
|
|
26
|
+
v_now := NOW() + INTERVAL '1 MILLISECOND' * p_delay_ms;
|
|
27
|
+
|
|
28
|
+
SELECT
|
|
29
|
+
"max_size",
|
|
30
|
+
"max_concurrency"
|
|
31
|
+
FROM ${t(e.schema)}."channel_policy"
|
|
32
|
+
WHERE "name" = p_channel_name
|
|
33
|
+
FOR SHARE
|
|
34
|
+
INTO v_channel_policy;
|
|
35
|
+
|
|
36
|
+
INSERT INTO ${t(e.schema)}."channel_state" (
|
|
37
|
+
"name",
|
|
38
|
+
"current_size",
|
|
39
|
+
"current_concurrency",
|
|
40
|
+
"max_size",
|
|
41
|
+
"max_concurrency",
|
|
42
|
+
"message_next_id",
|
|
43
|
+
"message_next_dequeue_after"
|
|
44
|
+
) VALUES (
|
|
45
|
+
p_channel_name,
|
|
46
|
+
0,
|
|
47
|
+
0,
|
|
48
|
+
v_channel_policy."max_size",
|
|
49
|
+
v_channel_policy."max_concurrency",
|
|
50
|
+
NULL,
|
|
51
|
+
NULL
|
|
52
|
+
) ON CONFLICT ("name")
|
|
53
|
+
DO UPDATE SET "id" = EXCLUDED."id"
|
|
54
|
+
RETURNING
|
|
55
|
+
"id",
|
|
56
|
+
"current_size",
|
|
57
|
+
"current_concurrency",
|
|
58
|
+
"max_size",
|
|
59
|
+
"max_concurrency",
|
|
60
|
+
"message_next_id",
|
|
61
|
+
"message_next_dequeue_after"
|
|
62
|
+
INTO v_channel_state;
|
|
63
|
+
|
|
64
|
+
IF v_channel_state."current_size" >= v_channel_policy."max_size" THEN
|
|
65
|
+
RETURN JSONB_BUILD_OBJECT(
|
|
66
|
+
'result_code', ${s(1)}
|
|
67
|
+
);
|
|
68
|
+
END IF;
|
|
69
|
+
|
|
70
|
+
INSERT INTO ${t(e.schema)}."message" (
|
|
71
|
+
"channel_name",
|
|
72
|
+
"name",
|
|
73
|
+
"content",
|
|
74
|
+
"lock_ms",
|
|
75
|
+
"dequeue_after"
|
|
76
|
+
) VALUES (
|
|
77
|
+
p_channel_name,
|
|
78
|
+
p_name,
|
|
79
|
+
p_content,
|
|
80
|
+
p_lock_ms,
|
|
81
|
+
v_now + INTERVAL '1 MILLISECOND' * p_delay_ms
|
|
82
|
+
) ON CONFLICT ("channel_name", "name")
|
|
83
|
+
WHERE "num_attempts" = 0
|
|
84
|
+
DO UPDATE SET
|
|
85
|
+
"id" = EXCLUDED."id"
|
|
86
|
+
RETURNING
|
|
87
|
+
"id",
|
|
88
|
+
"dequeue_after"
|
|
89
|
+
INTO v_message;
|
|
90
|
+
|
|
91
|
+
IF v_message."id" IS NULL THEN
|
|
92
|
+
RETURN JSONB_BUILD_OBJECT(
|
|
93
|
+
'result_code', ${s(2)},
|
|
94
|
+
'id', v_message."id"
|
|
95
|
+
);
|
|
96
|
+
END IF;
|
|
97
|
+
|
|
98
|
+
IF
|
|
99
|
+
v_channel_state."message_next_id" IS NULL OR
|
|
100
|
+
v_channel_state."message_next_dequeue_after" > v_message."dequeue_after"
|
|
101
|
+
THEN
|
|
102
|
+
UPDATE ${t(e.schema)}."channel_state" SET
|
|
103
|
+
"current_size" = v_channel_state."current_size" + 1,
|
|
104
|
+
"message_next_id" = v_message."id",
|
|
105
|
+
"message_next_dequeue_after" = v_message."dequeue_after"
|
|
106
|
+
WHERE "id" = v_channel_state."id";
|
|
107
|
+
ELSE
|
|
108
|
+
UPDATE ${t(e.schema)}."channel_state" SET
|
|
109
|
+
"current_size" = v_channel_state."current_size" + 1
|
|
110
|
+
WHERE "id" = v_channel_state."id";
|
|
111
|
+
END IF;
|
|
112
|
+
|
|
113
|
+
PERFORM ${t(e.schema)}."wake"(GREATEST(0, p_delay_ms));
|
|
114
|
+
|
|
115
|
+
RETURN JSONB_BUILD_OBJECT(
|
|
116
|
+
'result_code', ${s(0)},
|
|
117
|
+
'id', v_message."id"
|
|
118
|
+
);
|
|
119
|
+
END;
|
|
120
|
+
$$ LANGUAGE plpgsql;
|
|
121
|
+
`]}};class i{schema;channelName;name;content;lockMs;delayMs;createdAt;constructor(e){let n=e.name??null,_=e.lockMs===void 0?B:Math.max(0,e.lockMs),c;if(e.priority)c=-T;else c=e.delayMs===void 0?S:Math.max(0,e.delayMs);this.schema=e.schema,this.channelName=e.channelName,this.content=e.content,this.name=n,this.lockMs=_,this.delayMs=c,this.createdAt=new Date}async execute(e){let n=await e.query(a`
|
|
122
|
+
SELECT ${t(this.schema)}."message_create"(
|
|
123
|
+
${s(this.channelName)},
|
|
124
|
+
${s(this.name)},
|
|
125
|
+
${s(this.content)},
|
|
126
|
+
${s(this.lockMs)}::BIGINT,
|
|
127
|
+
${s(this.delayMs)}::BIGINT
|
|
128
|
+
) AS "result"
|
|
129
|
+
`.value).then((_)=>_.rows[0].result);if(n.result_code===1)return{resultType:"MESSAGE_DROPPED"};else if(n.result_code===2)return{resultType:"MESSAGE_DEDUPLICATED",id:n.id};else if(n.result_code===0)return{resultType:"MESSAGE_CREATED",id:n.id};else throw new Error("Unexpected result")}}var __filename="/home/runner/work/lonnymq/lonnymq/src/migration/05-function-message-dequeue.ts";var P={name:r(__filename),sql:(e)=>{return[a`
|
|
130
|
+
CREATE FUNCTION ${t(e.schema)}."message_dequeue" ()
|
|
131
|
+
RETURNS JSONB AS $$
|
|
132
|
+
DECLARE
|
|
133
|
+
v_now TIMESTAMP;
|
|
134
|
+
v_dequeue_id UUID;
|
|
135
|
+
v_channel_state RECORD;
|
|
136
|
+
v_message_locked RECORD;
|
|
137
|
+
v_retry_after TIMESTAMP;
|
|
138
|
+
v_message_dequeue RECORD;
|
|
139
|
+
v_message_next_dequeue RECORD;
|
|
140
|
+
v_message_next_dequeue_after TIMESTAMP;
|
|
141
|
+
BEGIN
|
|
142
|
+
v_now := NOW();
|
|
143
|
+
v_dequeue_id := GEN_RANDOM_UUID();
|
|
144
|
+
|
|
145
|
+
SELECT
|
|
146
|
+
"id",
|
|
147
|
+
"name",
|
|
148
|
+
"state",
|
|
149
|
+
"content",
|
|
150
|
+
"channel_name",
|
|
151
|
+
"lock_ms",
|
|
152
|
+
"dequeue_after",
|
|
153
|
+
"num_attempts"
|
|
154
|
+
FROM ${t(e.schema)}."message"
|
|
155
|
+
WHERE "is_locked"
|
|
156
|
+
ORDER BY "dequeue_after" ASC
|
|
157
|
+
FOR UPDATE
|
|
158
|
+
SKIP LOCKED
|
|
159
|
+
LIMIT 1
|
|
160
|
+
INTO v_message_locked;
|
|
161
|
+
|
|
162
|
+
IF v_message_locked."dequeue_after" <= v_now THEN
|
|
163
|
+
UPDATE ${t(e.schema)}."message" SET
|
|
164
|
+
"num_attempts" = v_message_locked."num_attempts" + 1,
|
|
165
|
+
"dequeue_after" = v_now + (v_message_locked."lock_ms" * INTERVAL '1 millisecond'),
|
|
166
|
+
"dequeue_id" = v_dequeue_id
|
|
167
|
+
WHERE "id" = v_message_locked."id";
|
|
168
|
+
|
|
169
|
+
PERFORM ${t(e.schema)}."wake"(v_message_locked."lock_ms");
|
|
170
|
+
|
|
171
|
+
RETURN JSONB_BUILD_OBJECT(
|
|
172
|
+
'result_code', ${s(1)},
|
|
173
|
+
'id', v_message_locked.id,
|
|
174
|
+
'channel_name', v_message_locked.channel_name,
|
|
175
|
+
'state', v_message_locked.state,
|
|
176
|
+
'name', v_message_locked.name,
|
|
177
|
+
'dequeue_id', v_dequeue_id,
|
|
178
|
+
'content', v_message_locked.content,
|
|
179
|
+
'num_attempts', v_message_locked.num_attempts
|
|
180
|
+
);
|
|
181
|
+
END IF;
|
|
182
|
+
|
|
183
|
+
SELECT
|
|
184
|
+
"id",
|
|
185
|
+
"name",
|
|
186
|
+
"message_next_id",
|
|
187
|
+
"message_next_dequeue_after",
|
|
188
|
+
"current_concurrency"
|
|
189
|
+
FROM ${t(e.schema)}."channel_state"
|
|
190
|
+
WHERE "message_next_id" IS NOT NULL
|
|
191
|
+
AND ("max_concurrency" IS NULL OR "current_concurrency" < "max_concurrency")
|
|
192
|
+
ORDER BY "message_next_dequeue_after" ASC
|
|
193
|
+
FOR UPDATE
|
|
194
|
+
SKIP LOCKED
|
|
195
|
+
LIMIT 1
|
|
196
|
+
INTO v_channel_state;
|
|
197
|
+
|
|
198
|
+
IF v_channel_state."id" IS NULL OR v_channel_state."message_next_dequeue_after" > v_now THEN
|
|
199
|
+
v_retry_after := LEAST(
|
|
200
|
+
v_channel_state."message_next_dequeue_after",
|
|
201
|
+
v_message_locked."dequeue_after"
|
|
202
|
+
);
|
|
203
|
+
|
|
204
|
+
RETURN JSONB_BUILD_OBJECT(
|
|
205
|
+
'result_code', ${s(0)},
|
|
206
|
+
'retry_ms', CEIL(EXTRACT(MILLISECOND FROM v_retry_after - v_now))
|
|
207
|
+
);
|
|
208
|
+
END IF;
|
|
209
|
+
|
|
210
|
+
SELECT
|
|
211
|
+
"id",
|
|
212
|
+
"name",
|
|
213
|
+
"channel_name",
|
|
214
|
+
"content",
|
|
215
|
+
"num_attempts",
|
|
216
|
+
"state",
|
|
217
|
+
"lock_ms"
|
|
218
|
+
FROM ${t(e.schema)}."message"
|
|
219
|
+
WHERE "id" = v_channel_state."message_next_id"
|
|
220
|
+
INTO v_message_dequeue;
|
|
221
|
+
|
|
222
|
+
UPDATE ${t(e.schema)}."message" SET
|
|
223
|
+
"is_locked" = TRUE,
|
|
224
|
+
"num_attempts" = v_message_dequeue."num_attempts" + 1,
|
|
225
|
+
"dequeue_id" = v_dequeue_id,
|
|
226
|
+
"dequeue_after" = v_now + (v_message_dequeue."lock_ms" * INTERVAL '1 millisecond')
|
|
227
|
+
WHERE "id" = v_message_dequeue."id";
|
|
228
|
+
|
|
229
|
+
PERFORM ${t(e.schema)}."wake"(v_message_dequeue."lock_ms");
|
|
230
|
+
|
|
231
|
+
SELECT
|
|
232
|
+
"id",
|
|
233
|
+
"dequeue_after"
|
|
234
|
+
FROM ${t(e.schema)}."message"
|
|
235
|
+
WHERE NOT "is_locked"
|
|
236
|
+
AND "channel_name" = v_message_dequeue."channel_name"
|
|
237
|
+
ORDER BY "dequeue_after" ASC
|
|
238
|
+
LIMIT 1
|
|
239
|
+
INTO v_message_next_dequeue;
|
|
240
|
+
|
|
241
|
+
IF v_message_next_dequeue."id" IS NOT NULL THEN
|
|
242
|
+
v_message_next_dequeue_after := GREATEST(
|
|
243
|
+
v_message_next_dequeue."dequeue_after",
|
|
244
|
+
v_now
|
|
245
|
+
);
|
|
246
|
+
|
|
247
|
+
UPDATE ${t(e.schema)}."channel_state" SET
|
|
248
|
+
"current_concurrency" = v_channel_state."current_concurrency" + 1,
|
|
249
|
+
"message_next_id" = v_message_next_dequeue."id",
|
|
250
|
+
"message_next_dequeue_after" = v_message_next_dequeue_after
|
|
251
|
+
WHERE "id" = v_channel_state."id";
|
|
252
|
+
ELSE
|
|
253
|
+
UPDATE ${t(e.schema)}."channel_state" SET
|
|
254
|
+
"current_concurrency" = v_channel_state."current_concurrency" + 1,
|
|
255
|
+
"message_next_id" = NULL
|
|
256
|
+
WHERE "id" = v_channel_state."id";
|
|
257
|
+
END IF;
|
|
258
|
+
|
|
259
|
+
|
|
260
|
+
RETURN JSONB_BUILD_OBJECT(
|
|
261
|
+
'result_code', ${s(1)},
|
|
262
|
+
'id', v_message_dequeue.id,
|
|
263
|
+
'channel_name', v_message_dequeue.channel_name,
|
|
264
|
+
'state', v_message_dequeue.state,
|
|
265
|
+
'dequeue_id', v_dequeue_id,
|
|
266
|
+
'name', v_message_dequeue.name,
|
|
267
|
+
'content', v_message_dequeue.content,
|
|
268
|
+
'num_attempts', v_message_dequeue.num_attempts
|
|
269
|
+
);
|
|
270
|
+
END;
|
|
271
|
+
$$ LANGUAGE plpgsql;
|
|
272
|
+
`]}};class l{schema;constructor(e){this.schema=e.schema}async execute(e){let n=await e.query(a`
|
|
273
|
+
SELECT ${t(this.schema)}."message_dequeue"() AS "result"
|
|
274
|
+
`.value).then((_)=>_.rows[0].result);if(n.result_code===0)return{resultType:"MESSAGE_NOT_AVAILABLE",retryMs:n.retry_ms};else if(n.result_code===1)return{resultType:"MESSAGE_DEQUEUED",message:{id:n.id,channelName:n.channel_name,name:n.name,content:n.content,dequeueId:n.dequeue_id,state:n.state,numAttempts:n.num_attempts,lockMs:n.lock_ms}};else throw new Error("Unexpected dequeue result")}}var __filename="/home/runner/work/lonnymq/lonnymq/src/migration/06-function-message-delete.ts";var k={name:r(__filename),sql:(e)=>{return[a`
|
|
275
|
+
CREATE FUNCTION ${t(e.schema)}."message_delete" (
|
|
276
|
+
p_id UUID,
|
|
277
|
+
p_dequeue_id UUID
|
|
278
|
+
)
|
|
279
|
+
RETURNS JSONB AS $$
|
|
280
|
+
DECLARE
|
|
281
|
+
v_channel_state RECORD;
|
|
282
|
+
v_message RECORD;
|
|
283
|
+
BEGIN
|
|
284
|
+
SELECT
|
|
285
|
+
"id",
|
|
286
|
+
"channel_name",
|
|
287
|
+
"dequeue_id"
|
|
288
|
+
FROM ${t(e.schema)}."message"
|
|
289
|
+
WHERE "id" = p_id
|
|
290
|
+
FOR UPDATE
|
|
291
|
+
INTO v_message;
|
|
292
|
+
|
|
293
|
+
IF v_message."id" IS NULL THEN
|
|
294
|
+
RETURN JSONB_BUILD_OBJECT(
|
|
295
|
+
'result_code', ${s(0)}
|
|
296
|
+
);
|
|
297
|
+
ELSEIF v_message."dequeue_id" != p_dequeue_id THEN
|
|
298
|
+
RETURN JSONB_BUILD_OBJECT(
|
|
299
|
+
'result_code', ${s(1)}
|
|
300
|
+
);
|
|
301
|
+
END IF;
|
|
302
|
+
|
|
303
|
+
SELECT
|
|
304
|
+
"id",
|
|
305
|
+
"current_size",
|
|
306
|
+
"current_concurrency"
|
|
307
|
+
FROM ${t(e.schema)}."channel_state"
|
|
308
|
+
WHERE "name" = v_message."channel_name"
|
|
309
|
+
FOR UPDATE
|
|
310
|
+
INTO v_channel_state;
|
|
311
|
+
|
|
312
|
+
IF v_channel_state."current_size" = 1 THEN
|
|
313
|
+
DELETE FROM ${t(e.schema)}."channel_state"
|
|
314
|
+
WHERE "id" = v_channel_state."id";
|
|
315
|
+
ELSE
|
|
316
|
+
UPDATE ${t(e.schema)}."channel_state" SET
|
|
317
|
+
"current_concurrency" = v_channel_state."current_concurrency" - 1,
|
|
318
|
+
"current_size" = v_channel_state."current_size" - 1
|
|
319
|
+
WHERE "id" = v_channel_state."id";
|
|
320
|
+
END IF;
|
|
321
|
+
|
|
322
|
+
DELETE FROM ${t(e.schema)}."message"
|
|
323
|
+
WHERE "id" = p_id;
|
|
324
|
+
|
|
325
|
+
RETURN JSONB_BUILD_OBJECT(
|
|
326
|
+
'result_code', ${s(2)}
|
|
327
|
+
);
|
|
328
|
+
END;
|
|
329
|
+
$$ LANGUAGE plpgsql;
|
|
330
|
+
`]}};class d{schema;id;dequeueId;constructor(e){this.schema=e.schema,this.id=e.id,this.dequeueId=e.dequeueId}async execute(e){let n=await e.query(a`
|
|
331
|
+
SELECT ${t(this.schema)}."message_delete"( ${s(this.id)},
|
|
332
|
+
${s(this.dequeueId)}
|
|
333
|
+
) AS "result"
|
|
334
|
+
`.value).then((_)=>_.rows[0].result);if(n.result_code===0)return{resultType:"MESSAGE_NOT_FOUND"};else if(n.result_code===1)return{resultType:"STATE_INVALID"};else if(n.result_code===2)return{resultType:"MESSAGE_DELETED"};else throw new Error("Unexpected result")}}var __filename="/home/runner/work/lonnymq/lonnymq/src/migration/07-function-message-defer.ts";var b={name:r(__filename),sql:(e)=>{return[a`
|
|
335
|
+
CREATE FUNCTION ${t(e.schema)}."message_defer" (
|
|
336
|
+
p_id UUID,
|
|
337
|
+
p_dequeue_id UUID,
|
|
338
|
+
p_delay_ms BIGINT,
|
|
339
|
+
p_state TEXT
|
|
340
|
+
)
|
|
341
|
+
RETURNS JSONB AS $$
|
|
342
|
+
DECLARE
|
|
343
|
+
v_channel_state RECORD;
|
|
344
|
+
v_dequeue_after TIMESTAMP;
|
|
345
|
+
v_message RECORD;
|
|
346
|
+
BEGIN
|
|
347
|
+
SELECT
|
|
348
|
+
"id",
|
|
349
|
+
"channel_name",
|
|
350
|
+
"dequeue_id"
|
|
351
|
+
FROM ${t(e.schema)}."message"
|
|
352
|
+
WHERE "id" = p_id
|
|
353
|
+
FOR UPDATE
|
|
354
|
+
INTO v_message;
|
|
355
|
+
|
|
356
|
+
IF v_message."id" IS NULL THEN
|
|
357
|
+
RETURN JSONB_BUILD_OBJECT(
|
|
358
|
+
'result_code', ${s(0)}
|
|
359
|
+
);
|
|
360
|
+
ELSEIF v_message."dequeue_id" != p_dequeue_id THEN
|
|
361
|
+
RETURN JSONB_BUILD_OBJECT(
|
|
362
|
+
'result_code', ${s(1)}
|
|
363
|
+
);
|
|
364
|
+
END IF;
|
|
365
|
+
|
|
366
|
+
SELECT
|
|
367
|
+
"current_concurrency",
|
|
368
|
+
"message_next_id",
|
|
369
|
+
"message_next_dequeue_after"
|
|
370
|
+
FROM ${t(e.schema)}."channel_state"
|
|
371
|
+
WHERE "name" = v_message."channel_name"
|
|
372
|
+
FOR UPDATE
|
|
373
|
+
INTO v_channel_state;
|
|
374
|
+
|
|
375
|
+
v_dequeue_after := NOW() + INTERVAL '1 MILLISECOND' * p_delay_ms;
|
|
376
|
+
|
|
377
|
+
IF
|
|
378
|
+
v_channel_state."message_next_id" IS NULL OR
|
|
379
|
+
v_channel_state."message_next_dequeue_after" > v_dequeue_after
|
|
380
|
+
THEN
|
|
381
|
+
UPDATE ${t(e.schema)}."channel_state" SET
|
|
382
|
+
"current_concurrency" = v_channel_state."current_concurrency" - 1,
|
|
383
|
+
"message_next_id" = v_message."id",
|
|
384
|
+
"message_next_dequeue_after" = v_dequeue_after
|
|
385
|
+
WHERE "name" = v_message."channel_name";
|
|
386
|
+
ELSE
|
|
387
|
+
UPDATE ${t(e.schema)}."channel_state" SET
|
|
388
|
+
"current_concurrency" = v_channel_state."current_concurrency" - 1
|
|
389
|
+
WHERE "name" = v_message."channel_name";
|
|
390
|
+
END IF;
|
|
391
|
+
|
|
392
|
+
UPDATE ${t(e.schema)}."message" SET
|
|
393
|
+
"state" = p_state,
|
|
394
|
+
"is_locked" = FALSE,
|
|
395
|
+
"dequeue_after" = v_dequeue_after
|
|
396
|
+
WHERE "id" = p_id;
|
|
397
|
+
|
|
398
|
+
PERFORM ${t(e.schema)}."wake"(GREATEST(0, p_delay_ms));
|
|
399
|
+
|
|
400
|
+
RETURN JSONB_BUILD_OBJECT(
|
|
401
|
+
'result_code', ${s(2)}
|
|
402
|
+
);
|
|
403
|
+
END;
|
|
404
|
+
$$ LANGUAGE plpgsql;
|
|
405
|
+
`]}};class h{schema;id;dequeueId;delayMs;state;constructor(e){let n;if(e.priority)n=-T;else n=e.delayMs===void 0?S:Math.max(0,e.delayMs);this.schema=e.schema,this.id=e.id,this.dequeueId=e.dequeueId,this.delayMs=n,this.state=e.state??null}async execute(e){let n=await e.query(a`
|
|
406
|
+
SELECT ${t(this.schema)}."message_defer"(
|
|
407
|
+
${s(this.id)},
|
|
408
|
+
${s(this.dequeueId)},
|
|
409
|
+
${s(this.delayMs)}::BIGINT,
|
|
410
|
+
${s(this.state)}
|
|
411
|
+
) AS "result"
|
|
412
|
+
`.value).then((_)=>_.rows[0].result);if(n.result_code===0)return{resultType:"MESSAGE_NOT_FOUND"};else if(n.result_code===1)return{resultType:"STATE_INVALID"};else if(n.result_code===2)return{resultType:"MESSAGE_DEFERRED"};else throw new Error("Unexpected result")}}var H=(e)=>{let n=e.split(`
|
|
413
|
+
`),_=Number.MAX_SAFE_INTEGER;for(let c of n){if(c.trim().length===0)continue;let u=c.search(/\S/);_=Math.min(_,u)}return n.map((c)=>c.slice(_)).join(`
|
|
414
|
+
`).trim()};var __filename="/home/runner/work/lonnymq/lonnymq/src/migration/00-table-channel-policy.ts",z={name:r(__filename),sql:(e)=>{return[a`
|
|
415
|
+
CREATE TABLE ${t(e.schema)}."channel_policy" (
|
|
416
|
+
"id" UUID NOT NULL DEFAULT GEN_RANDOM_UUID(),
|
|
417
|
+
"name" TEXT NOT NULL,
|
|
418
|
+
"max_size" BIGINT,
|
|
419
|
+
"max_concurrency" BIGINT,
|
|
420
|
+
PRIMARY KEY ("id")
|
|
421
|
+
);
|
|
422
|
+
`,a`
|
|
423
|
+
CREATE UNIQUE INDEX "channel_policy_name_ux"
|
|
424
|
+
ON ${t(e.schema)}."channel_policy" ("name");
|
|
425
|
+
`]}};var __filename="/home/runner/work/lonnymq/lonnymq/src/migration/01-table-channel-state.ts",w={name:r(__filename),sql:(e)=>{return[a`
|
|
426
|
+
CREATE TABLE ${t(e.schema)}."channel_state" (
|
|
427
|
+
"id" UUID NOT NULL DEFAULT GEN_RANDOM_UUID(),
|
|
428
|
+
"name" TEXT NOT NULL,
|
|
429
|
+
"max_size" BIGINT,
|
|
430
|
+
"max_concurrency" BIGINT,
|
|
431
|
+
"current_size" BIGINT NOT NULL,
|
|
432
|
+
"current_concurrency" BIGINT NOT NULL,
|
|
433
|
+
"message_next_id" UUID,
|
|
434
|
+
"message_next_dequeue_after" TIMESTAMP,
|
|
435
|
+
PRIMARY KEY ("id")
|
|
436
|
+
);
|
|
437
|
+
`,a`
|
|
438
|
+
CREATE UNIQUE INDEX "channel_state_name_ux"
|
|
439
|
+
ON ${t(e.schema)}."channel_state" ("name");
|
|
440
|
+
`,a`
|
|
441
|
+
CREATE INDEX "channel_state_dequeue_ix"
|
|
442
|
+
ON ${t(e.schema)}."channel_state" (
|
|
443
|
+
"message_next_dequeue_after" ASC
|
|
444
|
+
) WHERE "message_next_id" IS NOT NULL
|
|
445
|
+
AND ("max_concurrency" IS NULL OR "current_concurrency" < "max_concurrency");
|
|
446
|
+
`]}};var __filename="/home/runner/work/lonnymq/lonnymq/src/migration/02-table-message.ts",W={name:r(__filename),sql:(e)=>{return[a`
|
|
447
|
+
CREATE TABLE ${t(e.schema)}."message" (
|
|
448
|
+
"id" UUID NOT NULL DEFAULT GEN_RANDOM_UUID(),
|
|
449
|
+
"channel_name" TEXT NOT NULL,
|
|
450
|
+
"dequeue_id" UUID,
|
|
451
|
+
"name" TEXT,
|
|
452
|
+
"content" TEXT NOT NULL,
|
|
453
|
+
"state" TEXT,
|
|
454
|
+
"lock_ms" BIGINT NOT NULL,
|
|
455
|
+
"is_locked" BOOLEAN NOT NULL DEFAULT FALSE,
|
|
456
|
+
"num_attempts" BIGINT NOT NULL DEFAULT 0,
|
|
457
|
+
"dequeue_after" TIMESTAMP NOT NULL,
|
|
458
|
+
"sweep_after" TIMESTAMP,
|
|
459
|
+
PRIMARY KEY ("id")
|
|
460
|
+
);
|
|
461
|
+
`,a`
|
|
462
|
+
CREATE UNIQUE INDEX "message_name_ux"
|
|
463
|
+
ON ${t(e.schema)}."message" (
|
|
464
|
+
"channel_name",
|
|
465
|
+
"name"
|
|
466
|
+
) WHERE "num_attempts" = 0
|
|
467
|
+
`,a`
|
|
468
|
+
CREATE INDEX "message_dequeue_ix"
|
|
469
|
+
ON ${t(e.schema)}."message" (
|
|
470
|
+
"channel_name",
|
|
471
|
+
"dequeue_after" ASC
|
|
472
|
+
) WHERE NOT "is_locked";
|
|
473
|
+
`,a`
|
|
474
|
+
CREATE INDEX "message_locked_dequeue_ix"
|
|
475
|
+
ON ${t(e.schema)}."message" (
|
|
476
|
+
"dequeue_after" ASC
|
|
477
|
+
) WHERE "is_locked";
|
|
478
|
+
`]}};var __filename="/home/runner/work/lonnymq/lonnymq/src/migration/03-function-wake.ts",J={name:r(__filename),sql:(e)=>{let n=N.toString(e.schema);return[a`
|
|
479
|
+
CREATE FUNCTION ${t(e.schema)}."wake" (
|
|
480
|
+
p_delay_ms BIGINT
|
|
481
|
+
) RETURNS VOID AS $$
|
|
482
|
+
BEGIN
|
|
483
|
+
IF ${s(e.useWake)} THEN
|
|
484
|
+
PERFORM PG_NOTIFY(${s(n)}, p_delay_ms::TEXT);
|
|
485
|
+
END IF;
|
|
486
|
+
END;
|
|
487
|
+
$$ LANGUAGE plpgsql;
|
|
488
|
+
`]}};var __filename="/home/runner/work/lonnymq/lonnymq/src/migration/08-function-channel-policy-set.ts",V={name:r(__filename),sql:(e)=>{return[a`
|
|
489
|
+
CREATE FUNCTION ${t(e.schema)}."channel_policy_set" (
|
|
490
|
+
p_name TEXT,
|
|
491
|
+
p_max_size BIGINT,
|
|
492
|
+
p_max_concurrency BIGINT
|
|
493
|
+
) RETURNS VOID AS $$
|
|
494
|
+
BEGIN
|
|
495
|
+
INSERT INTO ${t(e.schema)}."channel_policy" (
|
|
496
|
+
"name",
|
|
497
|
+
"max_size",
|
|
498
|
+
"max_concurrency"
|
|
499
|
+
) VALUES (
|
|
500
|
+
p_name,
|
|
501
|
+
p_max_size,
|
|
502
|
+
p_max_concurrency
|
|
503
|
+
) ON CONFLICT ("name") DO UPDATE SET
|
|
504
|
+
"max_size" = EXCLUDED."max_size",
|
|
505
|
+
"max_concurrency" = EXCLUDED."max_concurrency";
|
|
506
|
+
|
|
507
|
+
UPDATE ${t(e.schema)}."channel_state" SET
|
|
508
|
+
"max_size" = p_max_size,
|
|
509
|
+
"max_concurrency" = p_max_concurrency
|
|
510
|
+
WHERE "name" = p_name;
|
|
511
|
+
|
|
512
|
+
PERFORM ${t(e.schema)}."wake"(0);
|
|
513
|
+
END;
|
|
514
|
+
$$ LANGUAGE plpgsql;
|
|
515
|
+
`]}};var __filename="/home/runner/work/lonnymq/lonnymq/src/migration/09-function-channel-policy-clear.ts",X={name:r(__filename),sql:(e)=>{return[a`
|
|
516
|
+
CREATE FUNCTION ${t(e.schema)}."channel_policy_clear" (
|
|
517
|
+
p_name TEXT
|
|
518
|
+
) RETURNS VOID AS $$
|
|
519
|
+
BEGIN
|
|
520
|
+
DELETE FROM ${t(e.schema)}."channel_policy"
|
|
521
|
+
WHERE "name" = p_name;
|
|
522
|
+
|
|
523
|
+
UPDATE ${t(e.schema)}."channel_state" SET
|
|
524
|
+
"max_size" = NULL,
|
|
525
|
+
"max_concurrency" = NULL
|
|
526
|
+
WHERE "name" = p_name;
|
|
527
|
+
|
|
528
|
+
PERFORM ${t(e.schema)}."wake"(0);
|
|
529
|
+
END;
|
|
530
|
+
$$ LANGUAGE plpgsql;
|
|
531
|
+
`]}};class m{value;isSet;constructor(){this.isSet=!1,this.value=null}get(){return this.isSet?{resultType:"RESULT_SET",value:this.value}:{resultType:"RESULT_NOT_SET"}}set(e){this.isSet=!0,this.value=e}}class O{schema;channelName;registerFn;constructor(e){this.schema=e.schema,this.channelName=e.channelName,this.registerFn=e.registerFn}create(e){let n=new i({schema:this.schema,channelName:this.channelName,name:e.name,content:e.content,lockMs:e.lockMs,delayMs:e.delayMs,priority:e.priority}),_=new m;return this.registerFn({sortKey:JSON.stringify([n.channelName,n.name,n.createdAt.toISOString()]),execute:(c)=>n.execute(c).then((u)=>_.set(u))}),_}}class D{schema;channelName;registerFn;constructor(e){this.schema=e.schema,this.channelName=e.channelName,this.registerFn=e.registerFn}set(e){let n=new o({schema:this.schema,channelName:this.channelName,maxConcurrency:e.maxConcurrency,maxSize:e.maxSize}),_=new m;return this.registerFn({sortKey:JSON.stringify([n.channelName,null,n.createdAt.toISOString()]),execute:(c)=>n.execute(c).then((u)=>_.set(u))}),_}clear(){let e=new E({schema:this.schema,channelName:this.channelName}),n=new m;return this.registerFn({sortKey:JSON.stringify([e.channelName,null,e.createdAt.toISOString()]),execute:(_)=>e.execute(_).then((c)=>n.set(c))}),n}}class L{policy;message;constructor(e){this.message=new O(e),this.policy=new D(e)}}var Ee=(e,n)=>{return e.sortKey.localeCompare(n.sortKey)};class U{commands;schema;constructor(e){this.commands=[],this.schema=e.schema}channel(e){return new L({schema:this.schema,channelName:e,registerFn:(n)=>{this.commands.push(n)}})}async execute(e){for(let n of this.commands.sort(Ee))await n.execute(e.databaseClient)}}class y{schema;channelName;constructor(e){this.schema=e.schema,this.channelName=e.channelName}async create(e){return new i({schema:this.schema,channelName:this.channelName,name:e.name,content:e.content,lockMs:e.lockMs,delayMs:e.delayMs,priority:e.priority}).execute(e.databaseClient)}}class x{schema;channelName;constructor(e){this.schema=e.schema,this.channelName=e.channelName}set(e){return new o({schema:this.schema,channelName:this.channelName,maxConcurrency:e.maxConcurrency,maxSize:e.maxSize}).execute(e.databaseClient)}clear(e){return new E({schema:this.schema,channelName:this.channelName}).execute(e.databaseClient)}}class v{policy;message;constructor(e){this.message=new y({schema:e.schema,channelName:e.channelName}),this.policy=new x({schema:e.schema,channelName:e.channelName})}}class f{schema;id;channelName;name;content;dequeueId;state;numAttempts;lockMs;constructor(e){this.schema=e.schema,this.id=e.id,this.channelName=e.channelName,this.dequeueId=e.dequeueId,this.name=e.name,this.content=e.content,this.state=e.state,this.numAttempts=e.numAttempts,this.lockMs=e.lockMs}async defer(e){return new h({schema:this.schema,id:this.id,dequeueId:this.dequeueId,delayMs:e.delayMs,state:e.state,priority:e.priority}).execute(e.databaseClient)}async delete(e){return new d({schema:this.schema,id:this.id,dequeueId:this.dequeueId}).execute(e.databaseClient)}}class p{schema;constructor(e){this.schema=e}async dequeue(e){let _=await new l({schema:this.schema}).execute(e.databaseClient);if(_.resultType==="MESSAGE_DEQUEUED")return{resultType:"MESSAGE_DEQUEUED",message:new f({schema:this.schema,id:_.message.id,dequeueId:_.message.dequeueId,channelName:_.message.channelName,name:_.message.name,content:_.message.content,state:_.message.state,numAttempts:_.message.numAttempts,lockMs:_.message.lockMs})};else return _}channel(e){return new v({schema:this.schema,channelName:e})}batch(){return new U({schema:this.schema})}migrations(e){return[z,w,W,J,G,P,k,b,V,X].map((n)=>({name:n.name,sql:n.sql({schema:this.schema,useWake:e.useWake??M}).map((_)=>H(_.value))})).sort((n,_)=>n.name.localeCompare(_.name))}wakeChannel(){return N.toString(this.schema)}}
|