@fedify/postgres 2.0.0-dev.241 → 2.0.0-dev.279
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/dist/mq.cjs +56 -16
- package/dist/mq.js +56 -16
- package/package.json +8 -6
package/dist/mq.cjs
CHANGED
|
@@ -46,46 +46,66 @@ var PostgresMessageQueue = class {
|
|
|
46
46
|
async enqueue(message, options) {
|
|
47
47
|
await this.initialize();
|
|
48
48
|
const delay = options?.delay ?? Temporal.Duration.from({ seconds: 0 });
|
|
49
|
+
const orderingKey = options?.orderingKey ?? null;
|
|
49
50
|
if (options?.delay) logger.debug("Enqueuing a message with a delay of {delay}...", {
|
|
50
51
|
delay,
|
|
51
|
-
message
|
|
52
|
+
message,
|
|
53
|
+
orderingKey
|
|
54
|
+
});
|
|
55
|
+
else logger.debug("Enqueuing a message...", {
|
|
56
|
+
message,
|
|
57
|
+
orderingKey
|
|
52
58
|
});
|
|
53
|
-
else logger.debug("Enqueuing a message...", { message });
|
|
54
59
|
await this.#sql`
|
|
55
|
-
INSERT INTO ${this.#sql(this.#tableName)} (message, delay)
|
|
60
|
+
INSERT INTO ${this.#sql(this.#tableName)} (message, delay, ordering_key)
|
|
56
61
|
VALUES (
|
|
57
62
|
${this.#json(message)},
|
|
58
|
-
${delay.toString()}
|
|
63
|
+
${delay.toString()},
|
|
64
|
+
${orderingKey}
|
|
59
65
|
);
|
|
60
66
|
`;
|
|
61
|
-
logger.debug("Enqueued a message.", {
|
|
67
|
+
logger.debug("Enqueued a message.", {
|
|
68
|
+
message,
|
|
69
|
+
orderingKey
|
|
70
|
+
});
|
|
62
71
|
await this.#sql.notify(this.#channelName, delay.toString());
|
|
63
72
|
logger.debug("Notified the message queue channel {channelName}.", {
|
|
64
73
|
channelName: this.#channelName,
|
|
65
|
-
message
|
|
74
|
+
message,
|
|
75
|
+
orderingKey
|
|
66
76
|
});
|
|
67
77
|
}
|
|
68
78
|
async enqueueMany(messages, options) {
|
|
69
79
|
if (messages.length === 0) return;
|
|
70
80
|
await this.initialize();
|
|
71
81
|
const delay = options?.delay ?? Temporal.Duration.from({ seconds: 0 });
|
|
82
|
+
const orderingKey = options?.orderingKey ?? null;
|
|
72
83
|
if (options?.delay) logger.debug("Enqueuing messages with a delay of {delay}...", {
|
|
73
84
|
delay,
|
|
74
|
-
messages
|
|
85
|
+
messages,
|
|
86
|
+
orderingKey
|
|
87
|
+
});
|
|
88
|
+
else logger.debug("Enqueuing messages...", {
|
|
89
|
+
messages,
|
|
90
|
+
orderingKey
|
|
75
91
|
});
|
|
76
|
-
else logger.debug("Enqueuing messages...", { messages });
|
|
77
92
|
for (const message of messages) await this.#sql`
|
|
78
|
-
INSERT INTO ${this.#sql(this.#tableName)} (message, delay)
|
|
93
|
+
INSERT INTO ${this.#sql(this.#tableName)} (message, delay, ordering_key)
|
|
79
94
|
VALUES (
|
|
80
95
|
${this.#json(message)},
|
|
81
|
-
${delay.toString()}
|
|
96
|
+
${delay.toString()},
|
|
97
|
+
${orderingKey}
|
|
82
98
|
);
|
|
83
99
|
`;
|
|
84
|
-
logger.debug("Enqueued messages.", {
|
|
100
|
+
logger.debug("Enqueued messages.", {
|
|
101
|
+
messages,
|
|
102
|
+
orderingKey
|
|
103
|
+
});
|
|
85
104
|
await this.#sql.notify(this.#channelName, delay.toString());
|
|
86
105
|
logger.debug("Notified the message queue channel {channelName}.", {
|
|
87
106
|
channelName: this.#channelName,
|
|
88
|
-
messages
|
|
107
|
+
messages,
|
|
108
|
+
orderingKey
|
|
89
109
|
});
|
|
90
110
|
}
|
|
91
111
|
async listen(handler, options = {}) {
|
|
@@ -99,17 +119,32 @@ var PostgresMessageQueue = class {
|
|
|
99
119
|
SELECT id
|
|
100
120
|
FROM ${this.#sql(this.#tableName)}
|
|
101
121
|
WHERE created + delay < CURRENT_TIMESTAMP
|
|
122
|
+
AND (ordering_key IS NULL
|
|
123
|
+
OR pg_try_advisory_lock(
|
|
124
|
+
hashtext(${this.#tableName}),
|
|
125
|
+
hashtext(ordering_key)
|
|
126
|
+
))
|
|
102
127
|
ORDER BY created
|
|
103
128
|
LIMIT 1
|
|
104
129
|
)
|
|
105
|
-
RETURNING message;
|
|
130
|
+
RETURNING message, ordering_key;
|
|
106
131
|
`.execute();
|
|
107
132
|
const cancel = query.cancel.bind(query);
|
|
108
133
|
signal?.addEventListener("abort", cancel);
|
|
109
134
|
let i = 0;
|
|
110
|
-
for (const
|
|
135
|
+
for (const row of await query) {
|
|
111
136
|
if (signal?.aborted) return;
|
|
112
|
-
|
|
137
|
+
const orderingKey = row.ordering_key;
|
|
138
|
+
try {
|
|
139
|
+
await handler(row.message);
|
|
140
|
+
} finally {
|
|
141
|
+
if (orderingKey != null) await this.#sql`
|
|
142
|
+
SELECT pg_advisory_unlock(
|
|
143
|
+
hashtext(${this.#tableName}),
|
|
144
|
+
hashtext(${orderingKey})
|
|
145
|
+
);
|
|
146
|
+
`;
|
|
147
|
+
}
|
|
113
148
|
i++;
|
|
114
149
|
}
|
|
115
150
|
signal?.removeEventListener("abort", cancel);
|
|
@@ -157,8 +192,13 @@ var PostgresMessageQueue = class {
|
|
|
157
192
|
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
158
193
|
message jsonb NOT NULL,
|
|
159
194
|
delay interval DEFAULT '0 seconds',
|
|
160
|
-
created timestamp with time zone DEFAULT CURRENT_TIMESTAMP
|
|
195
|
+
created timestamp with time zone DEFAULT CURRENT_TIMESTAMP,
|
|
196
|
+
ordering_key text
|
|
161
197
|
);
|
|
198
|
+
`;
|
|
199
|
+
await this.#sql`
|
|
200
|
+
ALTER TABLE ${this.#sql(this.#tableName)}
|
|
201
|
+
ADD COLUMN IF NOT EXISTS ordering_key text;
|
|
162
202
|
`;
|
|
163
203
|
} catch (error) {
|
|
164
204
|
if (!(error instanceof postgres.default.PostgresError && error.constraint_name === "pg_type_typname_nsp_index")) {
|
package/dist/mq.js
CHANGED
|
@@ -45,46 +45,66 @@ var PostgresMessageQueue = class {
|
|
|
45
45
|
async enqueue(message, options) {
|
|
46
46
|
await this.initialize();
|
|
47
47
|
const delay = options?.delay ?? Temporal.Duration.from({ seconds: 0 });
|
|
48
|
+
const orderingKey = options?.orderingKey ?? null;
|
|
48
49
|
if (options?.delay) logger.debug("Enqueuing a message with a delay of {delay}...", {
|
|
49
50
|
delay,
|
|
50
|
-
message
|
|
51
|
+
message,
|
|
52
|
+
orderingKey
|
|
53
|
+
});
|
|
54
|
+
else logger.debug("Enqueuing a message...", {
|
|
55
|
+
message,
|
|
56
|
+
orderingKey
|
|
51
57
|
});
|
|
52
|
-
else logger.debug("Enqueuing a message...", { message });
|
|
53
58
|
await this.#sql`
|
|
54
|
-
INSERT INTO ${this.#sql(this.#tableName)} (message, delay)
|
|
59
|
+
INSERT INTO ${this.#sql(this.#tableName)} (message, delay, ordering_key)
|
|
55
60
|
VALUES (
|
|
56
61
|
${this.#json(message)},
|
|
57
|
-
${delay.toString()}
|
|
62
|
+
${delay.toString()},
|
|
63
|
+
${orderingKey}
|
|
58
64
|
);
|
|
59
65
|
`;
|
|
60
|
-
logger.debug("Enqueued a message.", {
|
|
66
|
+
logger.debug("Enqueued a message.", {
|
|
67
|
+
message,
|
|
68
|
+
orderingKey
|
|
69
|
+
});
|
|
61
70
|
await this.#sql.notify(this.#channelName, delay.toString());
|
|
62
71
|
logger.debug("Notified the message queue channel {channelName}.", {
|
|
63
72
|
channelName: this.#channelName,
|
|
64
|
-
message
|
|
73
|
+
message,
|
|
74
|
+
orderingKey
|
|
65
75
|
});
|
|
66
76
|
}
|
|
67
77
|
async enqueueMany(messages, options) {
|
|
68
78
|
if (messages.length === 0) return;
|
|
69
79
|
await this.initialize();
|
|
70
80
|
const delay = options?.delay ?? Temporal.Duration.from({ seconds: 0 });
|
|
81
|
+
const orderingKey = options?.orderingKey ?? null;
|
|
71
82
|
if (options?.delay) logger.debug("Enqueuing messages with a delay of {delay}...", {
|
|
72
83
|
delay,
|
|
73
|
-
messages
|
|
84
|
+
messages,
|
|
85
|
+
orderingKey
|
|
86
|
+
});
|
|
87
|
+
else logger.debug("Enqueuing messages...", {
|
|
88
|
+
messages,
|
|
89
|
+
orderingKey
|
|
74
90
|
});
|
|
75
|
-
else logger.debug("Enqueuing messages...", { messages });
|
|
76
91
|
for (const message of messages) await this.#sql`
|
|
77
|
-
INSERT INTO ${this.#sql(this.#tableName)} (message, delay)
|
|
92
|
+
INSERT INTO ${this.#sql(this.#tableName)} (message, delay, ordering_key)
|
|
78
93
|
VALUES (
|
|
79
94
|
${this.#json(message)},
|
|
80
|
-
${delay.toString()}
|
|
95
|
+
${delay.toString()},
|
|
96
|
+
${orderingKey}
|
|
81
97
|
);
|
|
82
98
|
`;
|
|
83
|
-
logger.debug("Enqueued messages.", {
|
|
99
|
+
logger.debug("Enqueued messages.", {
|
|
100
|
+
messages,
|
|
101
|
+
orderingKey
|
|
102
|
+
});
|
|
84
103
|
await this.#sql.notify(this.#channelName, delay.toString());
|
|
85
104
|
logger.debug("Notified the message queue channel {channelName}.", {
|
|
86
105
|
channelName: this.#channelName,
|
|
87
|
-
messages
|
|
106
|
+
messages,
|
|
107
|
+
orderingKey
|
|
88
108
|
});
|
|
89
109
|
}
|
|
90
110
|
async listen(handler, options = {}) {
|
|
@@ -98,17 +118,32 @@ var PostgresMessageQueue = class {
|
|
|
98
118
|
SELECT id
|
|
99
119
|
FROM ${this.#sql(this.#tableName)}
|
|
100
120
|
WHERE created + delay < CURRENT_TIMESTAMP
|
|
121
|
+
AND (ordering_key IS NULL
|
|
122
|
+
OR pg_try_advisory_lock(
|
|
123
|
+
hashtext(${this.#tableName}),
|
|
124
|
+
hashtext(ordering_key)
|
|
125
|
+
))
|
|
101
126
|
ORDER BY created
|
|
102
127
|
LIMIT 1
|
|
103
128
|
)
|
|
104
|
-
RETURNING message;
|
|
129
|
+
RETURNING message, ordering_key;
|
|
105
130
|
`.execute();
|
|
106
131
|
const cancel = query.cancel.bind(query);
|
|
107
132
|
signal?.addEventListener("abort", cancel);
|
|
108
133
|
let i = 0;
|
|
109
|
-
for (const
|
|
134
|
+
for (const row of await query) {
|
|
110
135
|
if (signal?.aborted) return;
|
|
111
|
-
|
|
136
|
+
const orderingKey = row.ordering_key;
|
|
137
|
+
try {
|
|
138
|
+
await handler(row.message);
|
|
139
|
+
} finally {
|
|
140
|
+
if (orderingKey != null) await this.#sql`
|
|
141
|
+
SELECT pg_advisory_unlock(
|
|
142
|
+
hashtext(${this.#tableName}),
|
|
143
|
+
hashtext(${orderingKey})
|
|
144
|
+
);
|
|
145
|
+
`;
|
|
146
|
+
}
|
|
112
147
|
i++;
|
|
113
148
|
}
|
|
114
149
|
signal?.removeEventListener("abort", cancel);
|
|
@@ -156,8 +191,13 @@ var PostgresMessageQueue = class {
|
|
|
156
191
|
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
157
192
|
message jsonb NOT NULL,
|
|
158
193
|
delay interval DEFAULT '0 seconds',
|
|
159
|
-
created timestamp with time zone DEFAULT CURRENT_TIMESTAMP
|
|
194
|
+
created timestamp with time zone DEFAULT CURRENT_TIMESTAMP,
|
|
195
|
+
ordering_key text
|
|
160
196
|
);
|
|
197
|
+
`;
|
|
198
|
+
await this.#sql`
|
|
199
|
+
ALTER TABLE ${this.#sql(this.#tableName)}
|
|
200
|
+
ADD COLUMN IF NOT EXISTS ordering_key text;
|
|
161
201
|
`;
|
|
162
202
|
} catch (error) {
|
|
163
203
|
if (!(error instanceof postgres.PostgresError && error.constraint_name === "pg_type_typname_nsp_index")) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fedify/postgres",
|
|
3
|
-
"version": "2.0.0-dev.
|
|
3
|
+
"version": "2.0.0-dev.279+ce1bdc22",
|
|
4
4
|
"description": "PostgreSQL drivers for Fedify",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"fedify",
|
|
@@ -74,20 +74,22 @@
|
|
|
74
74
|
},
|
|
75
75
|
"peerDependencies": {
|
|
76
76
|
"postgres": "^3.4.7",
|
|
77
|
-
"@fedify/fedify": "^2.0.0-dev.
|
|
77
|
+
"@fedify/fedify": "^2.0.0-dev.279+ce1bdc22"
|
|
78
78
|
},
|
|
79
79
|
"devDependencies": {
|
|
80
80
|
"@std/async": "npm:@jsr/std__async@^1.0.13",
|
|
81
81
|
"tsdown": "^0.12.9",
|
|
82
82
|
"typescript": "^5.9.3",
|
|
83
|
-
"@fedify/
|
|
84
|
-
"@fedify/
|
|
83
|
+
"@fedify/fixture": "^2.0.0",
|
|
84
|
+
"@fedify/testing": "^2.0.0-dev.279+ce1bdc22"
|
|
85
85
|
},
|
|
86
86
|
"scripts": {
|
|
87
87
|
"build:self": "tsdown",
|
|
88
88
|
"build": "pnpm --filter @fedify/postgres... run build:self",
|
|
89
89
|
"prepublish": "pnpm build",
|
|
90
|
-
"
|
|
91
|
-
"test
|
|
90
|
+
"pretest": "pnpm build",
|
|
91
|
+
"test": "node --experimental-transform-types --test",
|
|
92
|
+
"pretest:bun": "pnpm build",
|
|
93
|
+
"test:bun": "bun test --timeout=10000"
|
|
92
94
|
}
|
|
93
95
|
}
|