@fedify/postgres 2.0.0-dev.237 → 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.
Files changed (3) hide show
  1. package/dist/mq.cjs +56 -16
  2. package/dist/mq.js +56 -16
  3. package/package.json +10 -7
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.", { 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.", { 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 message of await query) {
135
+ for (const row of await query) {
111
136
  if (signal?.aborted) return;
112
- await handler(message.message);
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.", { 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.", { 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 message of await query) {
134
+ for (const row of await query) {
110
135
  if (signal?.aborted) return;
111
- await handler(message.message);
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.237+7f2bb1de",
3
+ "version": "2.0.0-dev.279+ce1bdc22",
4
4
  "description": "PostgreSQL drivers for Fedify",
5
5
  "keywords": [
6
6
  "fedify",
@@ -74,19 +74,22 @@
74
74
  },
75
75
  "peerDependencies": {
76
76
  "postgres": "^3.4.7",
77
- "@fedify/fedify": "^2.0.0-dev.237+7f2bb1de"
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
83
  "@fedify/fixture": "^2.0.0",
84
- "@fedify/testing": "^2.0.0-dev.237+7f2bb1de"
84
+ "@fedify/testing": "^2.0.0-dev.279+ce1bdc22"
85
85
  },
86
86
  "scripts": {
87
- "build": "tsdown",
88
- "prepublish": "tsdown",
89
- "test": "tsdown && node --experimental-transform-types --test",
90
- "test:bun": "tsdown && bun test --timeout=10000"
87
+ "build:self": "tsdown",
88
+ "build": "pnpm --filter @fedify/postgres... run build:self",
89
+ "prepublish": "pnpm build",
90
+ "pretest": "pnpm build",
91
+ "test": "node --experimental-transform-types --test",
92
+ "pretest:bun": "pnpm build",
93
+ "test:bun": "bun test --timeout=10000"
91
94
  }
92
95
  }