Skip to content

Commit 1a9ef3d

Browse files
committed
trying to fix redis memory leak
1 parent 83d4a0a commit 1a9ef3d

File tree

2 files changed

+75
-5
lines changed

2 files changed

+75
-5
lines changed

packages/extension-redis/src/Redis.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,9 @@ export class Redis implements Extension {
134134
}
135135
this.sub.on('messageBuffer', this.handleIncomingMessage)
136136

137-
this.redlock = new Redlock([this.pub])
137+
this.redlock = new Redlock([this.pub], {
138+
retryCount: 0,
139+
})
138140

139141
const identifierBuffer = Buffer.from(this.configuration.identifier, 'utf-8')
140142
this.messagePrefix = Buffer.concat([Buffer.from([identifierBuffer.length]), identifierBuffer])
@@ -224,12 +226,14 @@ export class Redis implements Extension {
224226
async onStoreDocument({ documentName }: onStoreDocumentPayload) {
225227
// Attempt to acquire a lock and read lastReceivedTimestamp from Redis,
226228
// to avoid conflict with other instances storing the same document.
229+
227230
return new Promise((resolve, reject) => {
228231
this.redlock.lock(this.lockKey(documentName), this.configuration.lockTimeout, async (error, lock) => {
229232
if (error || !lock) {
230233
// Expected behavior: Could not acquire lock, another instance locked it already.
231234
// No further `onStoreDocument` hooks will be executed.
232-
reject(error)
235+
console.log('unable to acquire lock')
236+
reject()
233237
return
234238
}
235239

tests/extension-redis/onStoreDocument.ts

Lines changed: 69 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ test('stores documents without conflicts', async t => {
2424
new Redis({
2525
...redisConnectionSettings,
2626
identifier: `server${uuidv4()}`,
27-
prefix: 'extension-redis/onStoreDocument',
27+
prefix: 'extension-redis/onStoreDocument1',
2828
}),
2929
new CustomStorageExtension(),
3030
],
@@ -36,7 +36,7 @@ test('stores documents without conflicts', async t => {
3636
new Redis({
3737
...redisConnectionSettings,
3838
identifier: `anotherServer${uuidv4()}`,
39-
prefix: 'extension-redis/onStoreDocument',
39+
prefix: 'extension-redis/onStoreDocument1',
4040
}),
4141
new CustomStorageExtension(),
4242
],
@@ -63,7 +63,7 @@ test('stores documents when the last client disconnects', async t => {
6363
const server = await newHocuspocus({
6464
extensions: [
6565
new Redis({
66-
prefix: 'extension-redis/onStoreDocument',
66+
prefix: 'extension-redis/onStoreDocument2',
6767
...redisConnectionSettings,
6868
}),
6969
],
@@ -85,3 +85,69 @@ test('stores documents when the last client disconnects', async t => {
8585
})
8686
})
8787
})
88+
89+
test('document gets unloaded on both servers after disconnection', async t => {
90+
await new Promise(async resolve => {
91+
class CustomStorageExtension {
92+
priority = 10
93+
94+
onStoreDocument({ document }: onStoreDocumentPayload) {
95+
console.log('storing')
96+
return new Promise(resolve2 => {
97+
setTimeout(() => {
98+
console.log('stored')
99+
100+
resolve2('')
101+
}, 3000)
102+
})
103+
}
104+
}
105+
106+
const server = await newHocuspocus({
107+
name: 'redis-1',
108+
extensions: [
109+
new Redis({
110+
...redisConnectionSettings,
111+
prefix: 'extension-redis/onStoreDocument3',
112+
}),
113+
new CustomStorageExtension(),
114+
],
115+
})
116+
117+
const anotherServer = await newHocuspocus({
118+
name: 'redis-2',
119+
extensions: [
120+
new Redis({
121+
...redisConnectionSettings,
122+
prefix: 'extension-redis/onStoreDocument3',
123+
}),
124+
new CustomStorageExtension(),
125+
],
126+
})
127+
128+
const provider = newHocuspocusProvider(server)
129+
130+
const anotherProvider = newHocuspocusProvider(anotherServer, {
131+
onSynced() {
132+
// once we're setup make an edit on anotherProvider, if all succeeds the onStoreDocument
133+
// callback will be called after the debounce period and all docs will
134+
// be identical
135+
anotherProvider.document.getArray('foo').insert(0, ['bar'])
136+
provider.document.getArray('foo2').insert(0, ['bar'])
137+
138+
setTimeout(() => {
139+
provider.configuration.websocketProvider.disconnect()
140+
anotherProvider.configuration.websocketProvider.disconnect()
141+
142+
setTimeout(() => {
143+
t.is(anotherServer.documents.size, 0)
144+
t.is(server.documents.size, 0)
145+
146+
resolve('')
147+
}, 5000) // must be higher than RedisExtension.disconnectDelay
148+
}, 1500)
149+
150+
},
151+
})
152+
})
153+
})

0 commit comments

Comments
 (0)