@hocuspocus/extension-redis 3.2.4 → 3.2.6

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.
@@ -1,9 +1,9 @@
1
1
  'use strict';
2
2
 
3
+ var crypto = require('node:crypto');
3
4
  var server = require('@hocuspocus/server');
4
5
  var redlock = require('@sesamecare-oss/redlock');
5
6
  var RedisClient = require('ioredis');
6
- var uuid = require('uuid');
7
7
 
8
8
  class Redis {
9
9
  constructor(configuration) {
@@ -17,17 +17,12 @@ class Redis {
17
17
  port: 6379,
18
18
  host: "127.0.0.1",
19
19
  prefix: "hocuspocus",
20
- identifier: `host-${uuid.v4()}`,
20
+ identifier: `host-${crypto.randomUUID()}`,
21
21
  lockTimeout: 1000,
22
22
  disconnectDelay: 1000,
23
23
  };
24
24
  this.redisTransactionOrigin = "__hocuspocus__redis__origin__";
25
25
  this.locks = new Map();
26
- /**
27
- * When we have a high frequency of updates to a document we don't need tons of setTimeouts
28
- * piling up, so we'll track them to keep it to the most recent per document.
29
- */
30
- this.pendingDisconnects = new Map();
31
26
  this.pendingAfterStoreDocumentResolves = new Map();
32
27
  /**
33
28
  * Handle incoming messages published on subscribed document channels.
@@ -50,37 +45,6 @@ class Redis {
50
45
  return this.pub.publish(this.pubKey(document.name), this.encodeMessage(reply));
51
46
  });
52
47
  };
53
- /**
54
- * Make sure to *not* listen for further changes, when there’s
55
- * no one connected anymore.
56
- */
57
- this.onDisconnect = async ({ documentName }) => {
58
- const pending = this.pendingDisconnects.get(documentName);
59
- if (pending) {
60
- clearTimeout(pending);
61
- this.pendingDisconnects.delete(documentName);
62
- }
63
- const disconnect = () => {
64
- const document = this.instance.documents.get(documentName);
65
- this.pendingDisconnects.delete(documentName);
66
- // Do nothing, when other users are still connected to the document.
67
- if (document && document.getConnectionsCount() > 0) {
68
- return;
69
- }
70
- // Time to end the subscription on the document channel.
71
- this.sub.unsubscribe(this.subKey(documentName), (error) => {
72
- if (error) {
73
- console.error(error);
74
- }
75
- });
76
- if (document) {
77
- this.instance.unloadDocument(document);
78
- }
79
- };
80
- // Delay the disconnect procedure to allow last minute syncs to happen
81
- const timeout = setTimeout(disconnect, this.configuration.disconnectDelay);
82
- this.pendingDisconnects.set(documentName, timeout);
83
- };
84
48
  this.configuration = {
85
49
  ...this.configuration,
86
50
  ...configuration,
@@ -105,7 +69,7 @@ class Redis {
105
69
  }
106
70
  this.sub.on("messageBuffer", this.handleIncomingMessage);
107
71
  this.redlock = new redlock.Redlock([this.pub], {
108
- driftFactor: 0.1
72
+ retryCount: 0,
109
73
  });
110
74
  const identifierBuffer = Buffer.from(this.configuration.identifier, "utf-8");
111
75
  this.messagePrefix = Buffer.concat([
@@ -179,32 +143,46 @@ class Redis {
179
143
  // to avoid conflict with other instances storing the same document.
180
144
  const resource = this.lockKey(documentName);
181
145
  const ttl = this.configuration.lockTimeout;
182
- const lock = await this.redlock.acquire([resource], ttl);
183
- const oldLock = this.locks.get(resource);
184
- if (oldLock) {
185
- await oldLock.release;
146
+ try {
147
+ await this.redlock.acquire([resource], ttl);
148
+ const oldLock = this.locks.get(resource);
149
+ if (oldLock) {
150
+ await oldLock.release;
151
+ }
152
+ }
153
+ catch (error) {
154
+ //based on: https://github.com/sesamecare/redlock/blob/508e00dcd1e4d2bc6373ce455f4fe847e98a9aab/src/index.ts#L347-L349
155
+ if (error ==
156
+ "ExecutionError: The operation was unable to achieve a quorum during its retry window.") {
157
+ // Expected behavior: Could not acquire lock, another instance locked it already.
158
+ // No further `onStoreDocument` hooks will be executed; should throw a silent error with no message.
159
+ throw new Error("", {
160
+ cause: "Could not acquire lock, another instance locked it already.",
161
+ });
162
+ }
163
+ //unexpected error
164
+ console.error("unexpected error:", error);
165
+ throw error;
186
166
  }
187
- this.locks.set(resource, { lock });
188
167
  }
189
168
  /**
190
169
  * Release the Redis lock, so other instances can store documents.
191
170
  */
192
- async afterStoreDocument({ documentName, socketId }) {
171
+ async afterStoreDocument({ documentName, socketId, }) {
193
172
  const lockKey = this.lockKey(documentName);
194
173
  const lock = this.locks.get(lockKey);
195
- if (!lock) {
196
- throw new Error(`Lock created in onStoreDocument not found in afterStoreDocument: ${lockKey}`);
197
- }
198
- try {
199
- // Always try to unlock and clean up the lock
200
- lock.release = lock.lock.release();
201
- await lock.release;
202
- }
203
- catch {
204
- // Lock will expire on its own after timeout
205
- }
206
- finally {
207
- this.locks.delete(lockKey);
174
+ if (lock) {
175
+ try {
176
+ // Always try to unlock and clean up the lock
177
+ lock.release = lock.lock.release();
178
+ await lock.release;
179
+ }
180
+ catch {
181
+ // Lock will expire on its own after timeout
182
+ }
183
+ finally {
184
+ this.locks.delete(lockKey);
185
+ }
208
186
  }
209
187
  // if the change was initiated by a directConnection, we need to delay this hook to make sure sync can finish first.
210
188
  // for provider connections, this usually happens in the onDisconnect hook
@@ -246,6 +224,25 @@ class Redis {
246
224
  return this.publishFirstSyncStep(data.documentName, data.document);
247
225
  }
248
226
  }
227
+ /**
228
+ * Delay unloading to allow syncs to finish
229
+ */
230
+ async beforeUnloadDocument(data) {
231
+ return new Promise((resolve) => {
232
+ setTimeout(() => {
233
+ resolve();
234
+ }, this.configuration.disconnectDelay);
235
+ });
236
+ }
237
+ async afterUnloadDocument(data) {
238
+ if (data.instance.documents.has(data.documentName))
239
+ return; // skip unsubscribe if the document is already loaded again (maybe fast reconnect)
240
+ this.sub.unsubscribe(this.subKey(data.documentName), (error) => {
241
+ if (error) {
242
+ console.error(error);
243
+ }
244
+ });
245
+ }
249
246
  async beforeBroadcastStateless(data) {
250
247
  const message = new server.OutgoingMessage(data.documentName).writeBroadcastStateless(data.payload);
251
248
  return this.pub.publish(this.pubKey(data.documentName), this.encodeMessage(message.toUint8Array()));
@@ -1 +1 @@
1
- {"version":3,"file":"hocuspocus-redis.cjs","sources":["../src/Redis.ts"],"sourcesContent":[null],"names":["uuid","IncomingMessage","MessageReceiver","Redlock","OutgoingMessage"],"mappings":"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"}
1
+ {"version":3,"file":"hocuspocus-redis.cjs","sources":["../src/Redis.ts"],"sourcesContent":[null],"names":["IncomingMessage","MessageReceiver","Redlock","OutgoingMessage"],"mappings":"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"}
@@ -1,7 +1,7 @@
1
+ import crypto from 'node:crypto';
1
2
  import { IncomingMessage, MessageReceiver, OutgoingMessage } from '@hocuspocus/server';
2
3
  import { Redlock } from '@sesamecare-oss/redlock';
3
4
  import RedisClient from 'ioredis';
4
- import { v4 } from 'uuid';
5
5
 
6
6
  class Redis {
7
7
  constructor(configuration) {
@@ -15,17 +15,12 @@ class Redis {
15
15
  port: 6379,
16
16
  host: "127.0.0.1",
17
17
  prefix: "hocuspocus",
18
- identifier: `host-${v4()}`,
18
+ identifier: `host-${crypto.randomUUID()}`,
19
19
  lockTimeout: 1000,
20
20
  disconnectDelay: 1000,
21
21
  };
22
22
  this.redisTransactionOrigin = "__hocuspocus__redis__origin__";
23
23
  this.locks = new Map();
24
- /**
25
- * When we have a high frequency of updates to a document we don't need tons of setTimeouts
26
- * piling up, so we'll track them to keep it to the most recent per document.
27
- */
28
- this.pendingDisconnects = new Map();
29
24
  this.pendingAfterStoreDocumentResolves = new Map();
30
25
  /**
31
26
  * Handle incoming messages published on subscribed document channels.
@@ -48,37 +43,6 @@ class Redis {
48
43
  return this.pub.publish(this.pubKey(document.name), this.encodeMessage(reply));
49
44
  });
50
45
  };
51
- /**
52
- * Make sure to *not* listen for further changes, when there’s
53
- * no one connected anymore.
54
- */
55
- this.onDisconnect = async ({ documentName }) => {
56
- const pending = this.pendingDisconnects.get(documentName);
57
- if (pending) {
58
- clearTimeout(pending);
59
- this.pendingDisconnects.delete(documentName);
60
- }
61
- const disconnect = () => {
62
- const document = this.instance.documents.get(documentName);
63
- this.pendingDisconnects.delete(documentName);
64
- // Do nothing, when other users are still connected to the document.
65
- if (document && document.getConnectionsCount() > 0) {
66
- return;
67
- }
68
- // Time to end the subscription on the document channel.
69
- this.sub.unsubscribe(this.subKey(documentName), (error) => {
70
- if (error) {
71
- console.error(error);
72
- }
73
- });
74
- if (document) {
75
- this.instance.unloadDocument(document);
76
- }
77
- };
78
- // Delay the disconnect procedure to allow last minute syncs to happen
79
- const timeout = setTimeout(disconnect, this.configuration.disconnectDelay);
80
- this.pendingDisconnects.set(documentName, timeout);
81
- };
82
46
  this.configuration = {
83
47
  ...this.configuration,
84
48
  ...configuration,
@@ -103,7 +67,7 @@ class Redis {
103
67
  }
104
68
  this.sub.on("messageBuffer", this.handleIncomingMessage);
105
69
  this.redlock = new Redlock([this.pub], {
106
- driftFactor: 0.1
70
+ retryCount: 0,
107
71
  });
108
72
  const identifierBuffer = Buffer.from(this.configuration.identifier, "utf-8");
109
73
  this.messagePrefix = Buffer.concat([
@@ -177,32 +141,46 @@ class Redis {
177
141
  // to avoid conflict with other instances storing the same document.
178
142
  const resource = this.lockKey(documentName);
179
143
  const ttl = this.configuration.lockTimeout;
180
- const lock = await this.redlock.acquire([resource], ttl);
181
- const oldLock = this.locks.get(resource);
182
- if (oldLock) {
183
- await oldLock.release;
144
+ try {
145
+ await this.redlock.acquire([resource], ttl);
146
+ const oldLock = this.locks.get(resource);
147
+ if (oldLock) {
148
+ await oldLock.release;
149
+ }
150
+ }
151
+ catch (error) {
152
+ //based on: https://github.com/sesamecare/redlock/blob/508e00dcd1e4d2bc6373ce455f4fe847e98a9aab/src/index.ts#L347-L349
153
+ if (error ==
154
+ "ExecutionError: The operation was unable to achieve a quorum during its retry window.") {
155
+ // Expected behavior: Could not acquire lock, another instance locked it already.
156
+ // No further `onStoreDocument` hooks will be executed; should throw a silent error with no message.
157
+ throw new Error("", {
158
+ cause: "Could not acquire lock, another instance locked it already.",
159
+ });
160
+ }
161
+ //unexpected error
162
+ console.error("unexpected error:", error);
163
+ throw error;
184
164
  }
185
- this.locks.set(resource, { lock });
186
165
  }
187
166
  /**
188
167
  * Release the Redis lock, so other instances can store documents.
189
168
  */
190
- async afterStoreDocument({ documentName, socketId }) {
169
+ async afterStoreDocument({ documentName, socketId, }) {
191
170
  const lockKey = this.lockKey(documentName);
192
171
  const lock = this.locks.get(lockKey);
193
- if (!lock) {
194
- throw new Error(`Lock created in onStoreDocument not found in afterStoreDocument: ${lockKey}`);
195
- }
196
- try {
197
- // Always try to unlock and clean up the lock
198
- lock.release = lock.lock.release();
199
- await lock.release;
200
- }
201
- catch {
202
- // Lock will expire on its own after timeout
203
- }
204
- finally {
205
- this.locks.delete(lockKey);
172
+ if (lock) {
173
+ try {
174
+ // Always try to unlock and clean up the lock
175
+ lock.release = lock.lock.release();
176
+ await lock.release;
177
+ }
178
+ catch {
179
+ // Lock will expire on its own after timeout
180
+ }
181
+ finally {
182
+ this.locks.delete(lockKey);
183
+ }
206
184
  }
207
185
  // if the change was initiated by a directConnection, we need to delay this hook to make sure sync can finish first.
208
186
  // for provider connections, this usually happens in the onDisconnect hook
@@ -244,6 +222,25 @@ class Redis {
244
222
  return this.publishFirstSyncStep(data.documentName, data.document);
245
223
  }
246
224
  }
225
+ /**
226
+ * Delay unloading to allow syncs to finish
227
+ */
228
+ async beforeUnloadDocument(data) {
229
+ return new Promise((resolve) => {
230
+ setTimeout(() => {
231
+ resolve();
232
+ }, this.configuration.disconnectDelay);
233
+ });
234
+ }
235
+ async afterUnloadDocument(data) {
236
+ if (data.instance.documents.has(data.documentName))
237
+ return; // skip unsubscribe if the document is already loaded again (maybe fast reconnect)
238
+ this.sub.unsubscribe(this.subKey(data.documentName), (error) => {
239
+ if (error) {
240
+ console.error(error);
241
+ }
242
+ });
243
+ }
247
244
  async beforeBroadcastStateless(data) {
248
245
  const message = new OutgoingMessage(data.documentName).writeBroadcastStateless(data.payload);
249
246
  return this.pub.publish(this.pubKey(data.documentName), this.encodeMessage(message.toUint8Array()));
@@ -1 +1 @@
1
- {"version":3,"file":"hocuspocus-redis.esm.js","sources":["../src/Redis.ts"],"sourcesContent":[null],"names":["uuid"],"mappings":"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"}
1
+ {"version":3,"file":"hocuspocus-redis.esm.js","sources":["../src/Redis.ts"],"sourcesContent":[null],"names":[],"mappings":";;;;;MAgFa,KAAK,CAAA;AAoCjB,IAAA,WAAA,CAAmB,aAAqC,EAAA;AAnCxD;;;;AAIG;QACH,IAAQ,CAAA,QAAA,GAAG,IAAI;AAEf,QAAA,IAAA,CAAA,aAAa,GAAkB;AAC9B,YAAA,IAAI,EAAE,IAAI;AACV,YAAA,IAAI,EAAE,WAAW;AACjB,YAAA,MAAM,EAAE,YAAY;AACpB,YAAA,UAAU,EAAE,CAAQ,KAAA,EAAA,MAAM,CAAC,UAAU,EAAE,CAAE,CAAA;AACzC,YAAA,WAAW,EAAE,IAAI;AACjB,YAAA,eAAe,EAAE,IAAI;SACrB;QAED,IAAsB,CAAA,sBAAA,GAAG,+BAA+B;AAUxD,QAAA,IAAA,CAAA,KAAK,GAAG,IAAI,GAAG,EAA8D;AAIrE,QAAA,IAAA,CAAA,iCAAiC,GAAG,IAAI,GAAG,EAGhD;AAoOH;;;;AAIG;AACK,QAAA,IAAA,CAAA,qBAAqB,GAAG,OAAO,OAAe,EAAE,IAAY,KAAI;AACvE,YAAA,MAAM,CAAC,UAAU,EAAE,aAAa,CAAC,GAAG,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC;YAE5D,IAAI,UAAU,KAAK,IAAI,CAAC,aAAa,CAAC,UAAU,EAAE;gBACjD;;AAGD,YAAA,MAAM,OAAO,GAAG,IAAI,eAAe,CAAC,aAAa,CAAC;AAClD,YAAA,MAAM,YAAY,GAAG,OAAO,CAAC,aAAa,EAAE;AAC5C,YAAA,OAAO,CAAC,cAAc,CAAC,YAAY,CAAC;AAEpC,YAAA,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,GAAG,CAAC,YAAY,CAAC;YAE1D,IAAI,CAAC,QAAQ,EAAE;gBACd;;AAGD,YAAA,IAAI,eAAe,CAAC,OAAO,EAAE,IAAI,CAAC,sBAAsB,CAAC,CAAC,KAAK,CAC9D,QAAQ,EACR,SAAS,EACT,CAAC,KAAK,KAAI;gBACT,OAAO,IAAI,CAAC,GAAG,CAAC,OAAO,CACtB,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,EAC1B,IAAI,CAAC,aAAa,CAAC,KAAK,CAAC,CACzB;AACF,aAAC,CACD;AACF,SAAC;QAjQA,IAAI,CAAC,aAAa,GAAG;YACpB,GAAG,IAAI,CAAC,aAAa;AACrB,YAAA,GAAG,aAAa;SAChB;;AAGD,QAAA,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,YAAY,EAAE,GACxD,IAAI,CAAC,aAAa;AAEnB,QAAA,IAAI,OAAO,YAAY,KAAK,UAAU,EAAE;AACvC,YAAA,IAAI,CAAC,GAAG,GAAG,YAAY,EAAE;AACzB,YAAA,IAAI,CAAC,GAAG,GAAG,YAAY,EAAE;;aACnB,IAAI,KAAK,EAAE;AACjB,YAAA,IAAI,CAAC,GAAG,GAAG,KAAK,CAAC,SAAS,EAAE;AAC5B,YAAA,IAAI,CAAC,GAAG,GAAG,KAAK,CAAC,SAAS,EAAE;;aACtB,IAAI,KAAK,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE;AACrC,YAAA,IAAI,CAAC,GAAG,GAAG,IAAI,WAAW,CAAC,OAAO,CAAC,KAAK,EAAE,OAAO,CAAC;AAClD,YAAA,IAAI,CAAC,GAAG,GAAG,IAAI,WAAW,CAAC,OAAO,CAAC,KAAK,EAAE,OAAO,CAAC;;aAC5C;AACN,YAAA,IAAI,CAAC,GAAG,GAAG,IAAI,WAAW,CAAC,IAAI,EAAE,IAAI,EAAE,OAAO,aAAP,OAAO,KAAA,MAAA,GAAP,OAAO,GAAI,EAAE,CAAC;AACrD,YAAA,IAAI,CAAC,GAAG,GAAG,IAAI,WAAW,CAAC,IAAI,EAAE,IAAI,EAAE,OAAO,aAAP,OAAO,KAAA,MAAA,GAAP,OAAO,GAAI,EAAE,CAAC;;QAEtD,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,eAAe,EAAE,IAAI,CAAC,qBAAqB,CAAC;QAExD,IAAI,CAAC,OAAO,GAAG,IAAI,OAAO,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE;AACtC,YAAA,UAAU,EAAE,CAAC;AACb,SAAA,CAAC;AAEF,QAAA,MAAM,gBAAgB,GAAG,MAAM,CAAC,IAAI,CACnC,IAAI,CAAC,aAAa,CAAC,UAAU,EAC7B,OAAO,CACP;AACD,QAAA,IAAI,CAAC,aAAa,GAAG,MAAM,CAAC,MAAM,CAAC;YAClC,MAAM,CAAC,IAAI,CAAC,CAAC,gBAAgB,CAAC,MAAM,CAAC,CAAC;YACtC,gBAAgB;AAChB,SAAA,CAAC;;AAGH,IAAA,MAAM,WAAW,CAAC,EAAE,QAAQ,EAAsB,EAAA;AACjD,QAAA,IAAI,CAAC,QAAQ,GAAG,QAAQ;;AAGjB,IAAA,MAAM,CAAC,YAAoB,EAAA;QAClC,OAAO,CAAA,EAAG,IAAI,CAAC,aAAa,CAAC,MAAM,CAAA,CAAA,EAAI,YAAY,CAAA,CAAE;;AAG9C,IAAA,MAAM,CAAC,YAAoB,EAAA;AAClC,QAAA,OAAO,IAAI,CAAC,MAAM,CAAC,YAAY,CAAC;;AAGzB,IAAA,MAAM,CAAC,YAAoB,EAAA;AAClC,QAAA,OAAO,IAAI,CAAC,MAAM,CAAC,YAAY,CAAC;;AAGzB,IAAA,OAAO,CAAC,YAAoB,EAAA;QACnC,OAAO,CAAA,EAAG,IAAI,CAAC,MAAM,CAAC,YAAY,CAAC,OAAO;;AAGnC,IAAA,aAAa,CAAC,OAAmB,EAAA;AACxC,QAAA,OAAO,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,aAAa,EAAE,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC;;AAGzD,IAAA,aAAa,CAAC,MAAc,EAAA;AACnC,QAAA,MAAM,gBAAgB,GAAG,MAAM,CAAC,CAAC,CAAC;AAClC,QAAA,MAAM,UAAU,GAAG,MAAM,CAAC,QAAQ,CAAC,OAAO,EAAE,CAAC,EAAE,gBAAgB,GAAG,CAAC,CAAC;AAEpE,QAAA,OAAO,CAAC,UAAU,EAAE,MAAM,CAAC,KAAK,CAAC,gBAAgB,GAAG,CAAC,CAAC,CAAC;;AAGxD;;AAEG;AACI,IAAA,MAAM,iBAAiB,CAAC,EAC9B,YAAY,EACZ,QAAQ,GACkB,EAAA;QAC1B,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,KAAI;;;AAGtC,YAAA,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,IAAI,CAAC,MAAM,CAAC,YAAY,CAAC,EAAE,OAAO,KAAU,KAAI;gBAClE,IAAI,KAAK,EAAE;oBACV,MAAM,CAAC,KAAK,CAAC;oBACb;;AAGD,gBAAA,IAAI,CAAC,oBAAoB,CAAC,YAAY,EAAE,QAAQ,CAAC;AACjD,gBAAA,IAAI,CAAC,kCAAkC,CAAC,YAAY,CAAC;gBAErD,OAAO,CAAC,SAAS,CAAC;AACnB,aAAC,CAAC;AACH,SAAC,CAAC;;AAGH;;AAEG;AACK,IAAA,MAAM,oBAAoB,CAAC,YAAoB,EAAE,QAAkB,EAAA;AAC1E,QAAA,MAAM,WAAW,GAAG,IAAI,eAAe,CAAC,YAAY;AAClD,aAAA,iBAAiB;aACjB,qBAAqB,CAAC,QAAQ,CAAC;QAEjC,OAAO,IAAI,CAAC,GAAG,CAAC,OAAO,CACtB,IAAI,CAAC,MAAM,CAAC,YAAY,CAAC,EACzB,IAAI,CAAC,aAAa,CAAC,WAAW,CAAC,YAAY,EAAE,CAAC,CAC9C;;AAGF;;AAEG;IACK,MAAM,kCAAkC,CAAC,YAAoB,EAAA;QACpE,MAAM,gBAAgB,GAAG,IAAI,eAAe,CAC3C,YAAY,CACZ,CAAC,mBAAmB,EAAE;QAEvB,OAAO,IAAI,CAAC,GAAG,CAAC,OAAO,CACtB,IAAI,CAAC,MAAM,CAAC,YAAY,CAAC,EACzB,IAAI,CAAC,aAAa,CAAC,gBAAgB,CAAC,YAAY,EAAE,CAAC,CACnD;;AAGF;;;AAGG;AACH,IAAA,MAAM,eAAe,CAAC,EAAE,YAAY,EAA0B,EAAA;;;QAG7D,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,YAAY,CAAC;AAC3C,QAAA,MAAM,GAAG,GAAG,IAAI,CAAC,aAAa,CAAC,WAAW;AAC1C,QAAA,IAAI;AACH,YAAA,MAAM,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,QAAQ,CAAC,EAAE,GAAG,CAAC;YAC3C,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAC;YACxC,IAAI,OAAO,EAAE;gBACZ,MAAM,OAAO,CAAC,OAAO;;;QAErB,OAAO,KAAK,EAAE;;AAEf,YAAA,IACC,KAAK;AACL,gBAAA,uFAAuF,EACtF;;;AAGD,gBAAA,MAAM,IAAI,KAAK,CAAC,EAAE,EAAE;AACnB,oBAAA,KAAK,EAAE,6DAA6D;AACpE,iBAAA,CAAC;;;AAGH,YAAA,OAAO,CAAC,KAAK,CAAC,mBAAmB,EAAE,KAAK,CAAC;AACzC,YAAA,MAAM,KAAK;;;AAIb;;AAEG;AACH,IAAA,MAAM,kBAAkB,CAAC,EACxB,YAAY,EACZ,QAAQ,GACmB,EAAA;QAC3B,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,YAAY,CAAC;QAC1C,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC;QACpC,IAAI,IAAI,EAAE;AACT,YAAA,IAAI;;gBAEH,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE;gBAClC,MAAM,IAAI,CAAC,OAAO;;AACjB,YAAA,MAAM;;;oBAEE;AACT,gBAAA,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,OAAO,CAAC;;;;;AAK5B,QAAA,IAAI,QAAQ,KAAK,QAAQ,EAAE;YAC1B,MAAM,OAAO,GAAG,IAAI,CAAC,iCAAiC,CAAC,GAAG,CAAC,YAAY,CAAC;YAExE,IAAI,OAAO,EAAE;AACZ,gBAAA,YAAY,CAAC,OAAO,CAAC,OAAO,CAAC;gBAC7B,OAAO,CAAC,OAAO,EAAE;AACjB,gBAAA,IAAI,CAAC,iCAAiC,CAAC,MAAM,CAAC,YAAY,CAAC;;AAG5D,YAAA,IAAI,eAAe,GAAe,MAAK,GAAG;YAC1C,MAAM,cAAc,GAAG,IAAI,OAAO,CAAO,CAAC,OAAO,KAAI;gBACpD,eAAe,GAAG,OAAO;AAC1B,aAAC,CAAC;AAEF,YAAA,MAAM,OAAO,GAAG,UAAU,CAAC,MAAK;AAC/B,gBAAA,IAAI,CAAC,iCAAiC,CAAC,MAAM,CAAC,YAAY,CAAC;AAC3D,gBAAA,eAAe,EAAE;AAClB,aAAC,EAAE,IAAI,CAAC,aAAa,CAAC,eAAe,CAAC;AAEtC,YAAA,IAAI,CAAC,iCAAiC,CAAC,GAAG,CAAC,YAAY,EAAE;gBACxD,OAAO;AACP,gBAAA,OAAO,EAAE,eAAe;AACxB,aAAA,CAAC;AAEF,YAAA,MAAM,cAAc;;;AAItB;;AAEG;AACH,IAAA,MAAM,iBAAiB,CAAC,EACvB,YAAY,EACZ,SAAS,EACT,KAAK,EACL,OAAO,EACP,OAAO,GACmB,EAAA;QAC1B,MAAM,cAAc,GAAG,KAAK,CAAC,MAAM,CAAC,OAAO,EAAE,OAAO,CAAC;AACrD,QAAA,MAAM,OAAO,GAAG,IAAI,eAAe,CAClC,YAAY,CACZ,CAAC,4BAA4B,CAAC,SAAS,EAAE,cAAc,CAAC;QAEzD,OAAO,IAAI,CAAC,GAAG,CAAC,OAAO,CACtB,IAAI,CAAC,MAAM,CAAC,YAAY,CAAC,EACzB,IAAI,CAAC,aAAa,CAAC,OAAO,CAAC,YAAY,EAAE,CAAC,CAC1C;;AAqCF;;AAEG;IACI,MAAM,QAAQ,CAAC,IAAqB,EAAA;QAC1C,IAAI,IAAI,CAAC,iBAAiB,KAAK,IAAI,CAAC,sBAAsB,EAAE;AAC3D,YAAA,OAAO,IAAI,CAAC,oBAAoB,CAAC,IAAI,CAAC,YAAY,EAAE,IAAI,CAAC,QAAQ,CAAC;;;AAIpE;;AAEG;IACH,MAAM,oBAAoB,CAAC,IAAiC,EAAA;AAC3D,QAAA,OAAO,IAAI,OAAO,CAAO,CAAC,OAAO,KAAI;YACpC,UAAU,CAAC,MAAK;AACf,gBAAA,OAAO,EAAE;AACV,aAAC,EAAE,IAAI,CAAC,aAAa,CAAC,eAAe,CAAC;AACvC,SAAC,CAAC;;IAGH,MAAM,mBAAmB,CAAC,IAAgC,EAAA;QACzD,IAAI,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,YAAY,CAAC;AAAE,YAAA,OAAO;AAE3D,QAAA,IAAI,CAAC,GAAG,CAAC,WAAW,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,YAAY,CAAC,EAAE,CAAC,KAAU,KAAI;YACnE,IAAI,KAAK,EAAE;AACV,gBAAA,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC;;AAEtB,SAAC,CAAC;;IAGH,MAAM,wBAAwB,CAAC,IAAqC,EAAA;AACnE,QAAA,MAAM,OAAO,GAAG,IAAI,eAAe,CAClC,IAAI,CAAC,YAAY,CACjB,CAAC,uBAAuB,CAAC,IAAI,CAAC,OAAO,CAAC;QAEvC,OAAO,IAAI,CAAC,GAAG,CAAC,OAAO,CACtB,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,YAAY,CAAC,EAC9B,IAAI,CAAC,aAAa,CAAC,OAAO,CAAC,YAAY,EAAE,CAAC,CAC1C;;AAGF;;AAEG;AACH,IAAA,MAAM,SAAS,GAAA;AACd,QAAA,MAAM,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE;AACzB,QAAA,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,KAAK,CAAC;AAC1B,QAAA,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,KAAK,CAAC;;AAE3B;;;;"}
@@ -1,5 +1,5 @@
1
- import type { Extension, Hocuspocus, afterLoadDocumentPayload, afterStoreDocumentPayload, beforeBroadcastStatelessPayload, onAwarenessUpdatePayload, onChangePayload, onConfigurePayload, onDisconnectPayload, onStoreDocumentPayload } from "@hocuspocus/server";
2
- import { Redlock, type ExecutionResult, type Lock } from '@sesamecare-oss/redlock';
1
+ import type { Extension, Hocuspocus, afterLoadDocumentPayload, afterStoreDocumentPayload, afterUnloadDocumentPayload, beforeBroadcastStatelessPayload, beforeUnloadDocumentPayload, onAwarenessUpdatePayload, onChangePayload, onConfigurePayload, onStoreDocumentPayload } from "@hocuspocus/server";
2
+ import { type ExecutionResult, type Lock, Redlock } from "@sesamecare-oss/redlock";
3
3
  import type { Cluster, ClusterNode, ClusterOptions, RedisOptions } from "ioredis";
4
4
  import RedisClient from "ioredis";
5
5
  export type RedisInstance = RedisClient | Cluster;
@@ -67,11 +67,6 @@ export declare class Redis implements Extension {
67
67
  release?: Promise<ExecutionResult>;
68
68
  }>;
69
69
  messagePrefix: Buffer;
70
- /**
71
- * When we have a high frequency of updates to a document we don't need tons of setTimeouts
72
- * piling up, so we'll track them to keep it to the most recent per document.
73
- */
74
- private pendingDisconnects;
75
70
  private pendingAfterStoreDocumentResolves;
76
71
  constructor(configuration: Partial<Configuration>);
77
72
  onConfigure({ instance }: onConfigurePayload): Promise<void>;
@@ -101,7 +96,7 @@ export declare class Redis implements Extension {
101
96
  /**
102
97
  * Release the Redis lock, so other instances can store documents.
103
98
  */
104
- afterStoreDocument({ documentName, socketId }: afterStoreDocumentPayload): Promise<void>;
99
+ afterStoreDocument({ documentName, socketId, }: afterStoreDocumentPayload): Promise<void>;
105
100
  /**
106
101
  * Handle awareness update messages received directly by this Hocuspocus instance.
107
102
  */
@@ -117,10 +112,10 @@ export declare class Redis implements Extension {
117
112
  */
118
113
  onChange(data: onChangePayload): Promise<any>;
119
114
  /**
120
- * Make sure to *not* listen for further changes, when there’s
121
- * no one connected anymore.
115
+ * Delay unloading to allow syncs to finish
122
116
  */
123
- onDisconnect: ({ documentName }: onDisconnectPayload) => Promise<void>;
117
+ beforeUnloadDocument(data: beforeUnloadDocumentPayload): Promise<void>;
118
+ afterUnloadDocument(data: afterUnloadDocumentPayload): Promise<void>;
124
119
  beforeBroadcastStateless(data: beforeBroadcastStatelessPayload): Promise<number>;
125
120
  /**
126
121
  * Kill the Redlock connection immediately.
@@ -1,6 +1,6 @@
1
- import type { Extension, onChangePayload, onConnectPayload, onLoadDocumentPayload, onDisconnectPayload } from "@hocuspocus/server";
2
- import type { Doc } from "yjs";
1
+ import type { Extension, onChangePayload, onConnectPayload, onDisconnectPayload, onLoadDocumentPayload } from "@hocuspocus/server";
3
2
  import type { Transformer } from "@hocuspocus/transformer";
3
+ import type { Doc } from "yjs";
4
4
  export declare enum Events {
5
5
  onChange = "change",
6
6
  onConnect = "connect",
@@ -2,6 +2,7 @@ import type WebSocket from "ws";
2
2
  import { Awareness } from "y-protocols/awareness";
3
3
  import { Doc } from "yjs";
4
4
  import type Connection from "./Connection.ts";
5
+ import { Mutex } from "async-mutex";
5
6
  export declare class Document extends Doc {
6
7
  awareness: Awareness;
7
8
  callbacks: {
@@ -16,6 +17,7 @@ export declare class Document extends Doc {
16
17
  name: string;
17
18
  isLoading: boolean;
18
19
  isDestroyed: boolean;
20
+ saveMutex: Mutex;
19
21
  /**
20
22
  * Constructor.
21
23
  */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hocuspocus/extension-redis",
3
- "version": "3.2.4",
3
+ "version": "3.2.6",
4
4
  "description": "Scale Hocuspocus horizontally with Redis",
5
5
  "homepage": "https://hocuspocus.dev",
6
6
  "keywords": [
@@ -31,12 +31,11 @@
31
31
  "@types/lodash.debounce": "^4.0.6"
32
32
  },
33
33
  "dependencies": {
34
- "@hocuspocus/server": "^3.2.4",
34
+ "@hocuspocus/server": "^3.2.6",
35
35
  "@sesamecare-oss/redlock": "^1.4.0",
36
36
  "ioredis": "^5.6.1",
37
37
  "kleur": "^4.1.4",
38
- "lodash.debounce": "^4.0.8",
39
- "uuid": "^13.0.0"
38
+ "lodash.debounce": "^4.0.8"
40
39
  },
41
40
  "peerDependencies": {
42
41
  "y-protocols": "^1.0.6",
package/src/Redis.ts CHANGED
@@ -1,14 +1,16 @@
1
+ import crypto from "node:crypto";
1
2
  import type {
2
3
  Document,
3
4
  Extension,
4
5
  Hocuspocus,
5
6
  afterLoadDocumentPayload,
6
7
  afterStoreDocumentPayload,
8
+ afterUnloadDocumentPayload,
7
9
  beforeBroadcastStatelessPayload,
10
+ beforeUnloadDocumentPayload,
8
11
  onAwarenessUpdatePayload,
9
12
  onChangePayload,
10
13
  onConfigurePayload,
11
- onDisconnectPayload,
12
14
  onStoreDocumentPayload,
13
15
  } from "@hocuspocus/server";
14
16
  import {
@@ -16,11 +18,19 @@ import {
16
18
  MessageReceiver,
17
19
  OutgoingMessage,
18
20
  } from "@hocuspocus/server";
19
- import {Redlock, type ExecutionResult, type Lock} from '@sesamecare-oss/redlock';
20
- import type {Cluster, ClusterNode, ClusterOptions, RedisOptions} from "ioredis";
21
+ import {
22
+ type ExecutionResult,
23
+ type Lock,
24
+ Redlock,
25
+ } from "@sesamecare-oss/redlock";
26
+ import type {
27
+ Cluster,
28
+ ClusterNode,
29
+ ClusterOptions,
30
+ RedisOptions,
31
+ } from "ioredis";
21
32
  import RedisClient from "ioredis";
22
- import {v4 as uuid} from "uuid";
23
- export type RedisInstance = RedisClient | Cluster
33
+ export type RedisInstance = RedisClient | Cluster;
24
34
  export interface Configuration {
25
35
  /**
26
36
  * Redis port
@@ -80,7 +90,7 @@ export class Redis implements Extension {
80
90
  port: 6379,
81
91
  host: "127.0.0.1",
82
92
  prefix: "hocuspocus",
83
- identifier: `host-${uuid()}`,
93
+ identifier: `host-${crypto.randomUUID()}`,
84
94
  lockTimeout: 1000,
85
95
  disconnectDelay: 1000,
86
96
  };
@@ -95,16 +105,10 @@ export class Redis implements Extension {
95
105
 
96
106
  redlock: Redlock;
97
107
 
98
- locks = new Map<string, {lock: Lock; release?: Promise<ExecutionResult>}>();
108
+ locks = new Map<string, { lock: Lock; release?: Promise<ExecutionResult> }>();
99
109
 
100
110
  messagePrefix: Buffer;
101
111
 
102
- /**
103
- * When we have a high frequency of updates to a document we don't need tons of setTimeouts
104
- * piling up, so we'll track them to keep it to the most recent per document.
105
- */
106
- private pendingDisconnects = new Map<string, NodeJS.Timeout>();
107
-
108
112
  private pendingAfterStoreDocumentResolves = new Map<
109
113
  string,
110
114
  { timeout: NodeJS.Timeout; resolve: () => void }
@@ -136,7 +140,7 @@ export class Redis implements Extension {
136
140
  this.sub.on("messageBuffer", this.handleIncomingMessage);
137
141
 
138
142
  this.redlock = new Redlock([this.pub], {
139
- driftFactor: 0.1
143
+ retryCount: 0,
140
144
  });
141
145
 
142
146
  const identifierBuffer = Buffer.from(
@@ -236,37 +240,55 @@ export class Redis implements Extension {
236
240
  * Before the document is stored, make sure to set a lock in Redis.
237
241
  * That’s meant to avoid conflicts with other instances trying to store the document.
238
242
  */
239
- async onStoreDocument({documentName}: onStoreDocumentPayload) {
240
- // Attempt to acquire a lock and read lastReceivedTimestamp from Redis,
241
- // to avoid conflict with other instances storing the same document.
242
- const resource = this.lockKey(documentName)
243
- const ttl = this.configuration.lockTimeout
244
- const lock = await this.redlock.acquire([resource], ttl)
245
- const oldLock = this.locks.get(resource)
246
- if (oldLock) {
247
- await oldLock.release
248
- }
249
- this.locks.set(resource, {lock})
250
- }
243
+ async onStoreDocument({ documentName }: onStoreDocumentPayload) {
244
+ // Attempt to acquire a lock and read lastReceivedTimestamp from Redis,
245
+ // to avoid conflict with other instances storing the same document.
246
+ const resource = this.lockKey(documentName);
247
+ const ttl = this.configuration.lockTimeout;
248
+ try {
249
+ await this.redlock.acquire([resource], ttl);
250
+ const oldLock = this.locks.get(resource);
251
+ if (oldLock) {
252
+ await oldLock.release;
253
+ }
254
+ } catch (error) {
255
+ //based on: https://github.com/sesamecare/redlock/blob/508e00dcd1e4d2bc6373ce455f4fe847e98a9aab/src/index.ts#L347-L349
256
+ if (
257
+ error ==
258
+ "ExecutionError: The operation was unable to achieve a quorum during its retry window."
259
+ ) {
260
+ // Expected behavior: Could not acquire lock, another instance locked it already.
261
+ // No further `onStoreDocument` hooks will be executed; should throw a silent error with no message.
262
+ throw new Error("", {
263
+ cause: "Could not acquire lock, another instance locked it already.",
264
+ });
265
+ }
266
+ //unexpected error
267
+ console.error("unexpected error:", error);
268
+ throw error;
269
+ }
270
+ }
251
271
 
252
272
  /**
253
273
  * Release the Redis lock, so other instances can store documents.
254
274
  */
255
- async afterStoreDocument({documentName, socketId}: afterStoreDocumentPayload) {
256
- const lockKey = this.lockKey(documentName)
257
- const lock = this.locks.get(lockKey)
258
- if (!lock) {
259
- throw new Error(`Lock created in onStoreDocument not found in afterStoreDocument: ${lockKey}`)
260
- }
261
- try {
262
- // Always try to unlock and clean up the lock
263
- lock.release = lock.lock.release()
264
- await lock.release
265
- } catch {
266
- // Lock will expire on its own after timeout
267
- } finally {
268
- this.locks.delete(lockKey)
269
- }
275
+ async afterStoreDocument({
276
+ documentName,
277
+ socketId,
278
+ }: afterStoreDocumentPayload) {
279
+ const lockKey = this.lockKey(documentName);
280
+ const lock = this.locks.get(lockKey);
281
+ if (lock) {
282
+ try {
283
+ // Always try to unlock and clean up the lock
284
+ lock.release = lock.lock.release();
285
+ await lock.release;
286
+ } catch {
287
+ // Lock will expire on its own after timeout
288
+ } finally {
289
+ this.locks.delete(lockKey);
290
+ }
291
+ }
270
292
  // if the change was initiated by a directConnection, we need to delay this hook to make sure sync can finish first.
271
293
  // for provider connections, this usually happens in the onDisconnect hook
272
294
  if (socketId === "server") {
@@ -362,42 +384,25 @@ export class Redis implements Extension {
362
384
  }
363
385
 
364
386
  /**
365
- * Make sure to *not* listen for further changes, when there’s
366
- * no one connected anymore.
387
+ * Delay unloading to allow syncs to finish
367
388
  */
368
- public onDisconnect = async ({ documentName }: onDisconnectPayload) => {
369
- const pending = this.pendingDisconnects.get(documentName);
370
-
371
- if (pending) {
372
- clearTimeout(pending);
373
- this.pendingDisconnects.delete(documentName);
374
- }
375
-
376
- const disconnect = () => {
377
- const document = this.instance.documents.get(documentName);
378
-
379
- this.pendingDisconnects.delete(documentName);
380
-
381
- // Do nothing, when other users are still connected to the document.
382
- if (document && document.getConnectionsCount() > 0) {
383
- return;
384
- }
389
+ async beforeUnloadDocument(data: beforeUnloadDocumentPayload) {
390
+ return new Promise<void>((resolve) => {
391
+ setTimeout(() => {
392
+ resolve();
393
+ }, this.configuration.disconnectDelay);
394
+ });
395
+ }
385
396
 
386
- // Time to end the subscription on the document channel.
387
- this.sub.unsubscribe(this.subKey(documentName), (error: any) => {
388
- if (error) {
389
- console.error(error);
390
- }
391
- });
397
+ async afterUnloadDocument(data: afterUnloadDocumentPayload) {
398
+ if (data.instance.documents.has(data.documentName)) return; // skip unsubscribe if the document is already loaded again (maybe fast reconnect)
392
399
 
393
- if(document) {
394
- this.instance.unloadDocument(document);
400
+ this.sub.unsubscribe(this.subKey(data.documentName), (error: any) => {
401
+ if (error) {
402
+ console.error(error);
395
403
  }
396
- };
397
- // Delay the disconnect procedure to allow last minute syncs to happen
398
- const timeout = setTimeout(disconnect, this.configuration.disconnectDelay);
399
- this.pendingDisconnects.set(documentName, timeout);
400
- };
404
+ });
405
+ }
401
406
 
402
407
  async beforeBroadcastStateless(data: beforeBroadcastStatelessPayload) {
403
408
  const message = new OutgoingMessage(