@fedify/postgres 2.0.1-dev.400 → 2.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/dist/mq.cjs +24 -5
  2. package/dist/mq.js +24 -5
  3. package/package.json +4 -4
package/dist/mq.cjs CHANGED
@@ -18,7 +18,12 @@ function sleep(milliseconds) {
18
18
  return new Promise((resolve) => setTimeout(resolve, milliseconds));
19
19
  }
20
20
  function isInitializationRaceError(error) {
21
- return error instanceof postgres.default.PostgresError && (error.constraint_name === "pg_type_typname_nsp_index" || error.code === "42P07" || error.code === "42710");
21
+ return error instanceof postgres.default.PostgresError && (error.constraint_name === "pg_type_typname_nsp_index" || error.constraint_name === "pg_class_relname_nsp_index" || error.code === "42P07" || error.code === "42710");
22
+ }
23
+ function getCreatedIndexName(tableName) {
24
+ let hash = 0;
25
+ for (let i = 0; i < tableName.length; i++) hash = hash * 31 + tableName.charCodeAt(i) >>> 0;
26
+ return `idx_fedify_mq_created_${hash.toString(16).padStart(8, "0")}`;
22
27
  }
23
28
  /**
24
29
  * A message queue that uses PostgreSQL as the underlying storage.
@@ -202,19 +207,29 @@ var PostgresMessageQueue = class {
202
207
  pollLock = next.catch(() => {});
203
208
  return next;
204
209
  };
210
+ const safeSerializedPoll = async (trigger) => {
211
+ try {
212
+ await serializedPoll();
213
+ } catch (error) {
214
+ logger.error("Error while polling for messages ({trigger}); will retry on next trigger: {error}", {
215
+ trigger,
216
+ error
217
+ });
218
+ }
219
+ };
205
220
  const timeouts = /* @__PURE__ */ new Set();
206
221
  const listen = await this.#sql.listen(this.#channelName, async (delay) => {
207
222
  const duration = Temporal.Duration.from(delay);
208
223
  const durationMs = duration.total("millisecond");
209
- if (durationMs < 1) await serializedPoll();
224
+ if (durationMs < 1) await safeSerializedPoll("notify-immediate");
210
225
  else {
211
226
  const timeout = setTimeout(() => {
212
227
  timeouts.delete(timeout);
213
- serializedPoll();
228
+ safeSerializedPoll("notify-delayed");
214
229
  }, durationMs);
215
230
  timeouts.add(timeout);
216
231
  }
217
- }, serializedPoll);
232
+ }, () => safeSerializedPoll("subscribe"));
218
233
  signal?.addEventListener("abort", () => {
219
234
  listen.unlisten();
220
235
  for (const timeout of timeouts) clearTimeout(timeout);
@@ -231,7 +246,7 @@ var PostgresMessageQueue = class {
231
246
  timeouts.add(timeout);
232
247
  });
233
248
  if (timeout != null) timeouts.delete(timeout);
234
- await serializedPoll();
249
+ await safeSerializedPoll("interval");
235
250
  }
236
251
  await new Promise((resolve) => {
237
252
  signal?.addEventListener("abort", () => resolve());
@@ -260,6 +275,10 @@ var PostgresMessageQueue = class {
260
275
  await this.#sql`
261
276
  ALTER TABLE ${this.#sql(this.#tableName)}
262
277
  ADD COLUMN IF NOT EXISTS ordering_key text;
278
+ `;
279
+ await this.#sql`
280
+ CREATE INDEX IF NOT EXISTS ${this.#sql(getCreatedIndexName(this.#tableName))}
281
+ ON ${this.#sql(this.#tableName)} (created);
263
282
  `;
264
283
  break;
265
284
  } catch (error) {
package/dist/mq.js CHANGED
@@ -17,7 +17,12 @@ function sleep(milliseconds) {
17
17
  return new Promise((resolve) => setTimeout(resolve, milliseconds));
18
18
  }
19
19
  function isInitializationRaceError(error) {
20
- return error instanceof postgres.PostgresError && (error.constraint_name === "pg_type_typname_nsp_index" || error.code === "42P07" || error.code === "42710");
20
+ return error instanceof postgres.PostgresError && (error.constraint_name === "pg_type_typname_nsp_index" || error.constraint_name === "pg_class_relname_nsp_index" || error.code === "42P07" || error.code === "42710");
21
+ }
22
+ function getCreatedIndexName(tableName) {
23
+ let hash = 0;
24
+ for (let i = 0; i < tableName.length; i++) hash = hash * 31 + tableName.charCodeAt(i) >>> 0;
25
+ return `idx_fedify_mq_created_${hash.toString(16).padStart(8, "0")}`;
21
26
  }
22
27
  /**
23
28
  * A message queue that uses PostgreSQL as the underlying storage.
@@ -201,19 +206,29 @@ var PostgresMessageQueue = class {
201
206
  pollLock = next.catch(() => {});
202
207
  return next;
203
208
  };
209
+ const safeSerializedPoll = async (trigger) => {
210
+ try {
211
+ await serializedPoll();
212
+ } catch (error) {
213
+ logger.error("Error while polling for messages ({trigger}); will retry on next trigger: {error}", {
214
+ trigger,
215
+ error
216
+ });
217
+ }
218
+ };
204
219
  const timeouts = /* @__PURE__ */ new Set();
205
220
  const listen = await this.#sql.listen(this.#channelName, async (delay) => {
206
221
  const duration = Temporal.Duration.from(delay);
207
222
  const durationMs = duration.total("millisecond");
208
- if (durationMs < 1) await serializedPoll();
223
+ if (durationMs < 1) await safeSerializedPoll("notify-immediate");
209
224
  else {
210
225
  const timeout = setTimeout(() => {
211
226
  timeouts.delete(timeout);
212
- serializedPoll();
227
+ safeSerializedPoll("notify-delayed");
213
228
  }, durationMs);
214
229
  timeouts.add(timeout);
215
230
  }
216
- }, serializedPoll);
231
+ }, () => safeSerializedPoll("subscribe"));
217
232
  signal?.addEventListener("abort", () => {
218
233
  listen.unlisten();
219
234
  for (const timeout of timeouts) clearTimeout(timeout);
@@ -230,7 +245,7 @@ var PostgresMessageQueue = class {
230
245
  timeouts.add(timeout);
231
246
  });
232
247
  if (timeout != null) timeouts.delete(timeout);
233
- await serializedPoll();
248
+ await safeSerializedPoll("interval");
234
249
  }
235
250
  await new Promise((resolve) => {
236
251
  signal?.addEventListener("abort", () => resolve());
@@ -259,6 +274,10 @@ var PostgresMessageQueue = class {
259
274
  await this.#sql`
260
275
  ALTER TABLE ${this.#sql(this.#tableName)}
261
276
  ADD COLUMN IF NOT EXISTS ordering_key text;
277
+ `;
278
+ await this.#sql`
279
+ CREATE INDEX IF NOT EXISTS ${this.#sql(getCreatedIndexName(this.#tableName))}
280
+ ON ${this.#sql(this.#tableName)} (created);
262
281
  `;
263
282
  break;
264
283
  } catch (error) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fedify/postgres",
3
- "version": "2.0.1-dev.400+51b2d013",
3
+ "version": "2.0.1",
4
4
  "description": "PostgreSQL drivers for Fedify",
5
5
  "keywords": [
6
6
  "fedify",
@@ -74,14 +74,14 @@
74
74
  },
75
75
  "peerDependencies": {
76
76
  "postgres": "^3.4.7",
77
- "@fedify/fedify": "^2.0.1-dev.400+51b2d013"
77
+ "@fedify/fedify": "^2.0.1"
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/fixture": "^2.0.0",
84
- "@fedify/testing": "^2.0.1-dev.400+51b2d013"
83
+ "@fedify/testing": "^2.0.1",
84
+ "@fedify/fixture": "^2.0.0"
85
85
  },
86
86
  "scripts": {
87
87
  "build:self": "tsdown",