Skip to content

Commit 2dedc84

Browse files
committed
refactor(realtime): extract "save note as revision" to job
Signed-off-by: BoHong Li <[email protected]>
1 parent ab37a33 commit 2dedc84

File tree

8 files changed

+155
-34
lines changed

8 files changed

+155
-34
lines changed

lib/realtime.js

Lines changed: 11 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ const { ProcessQueue } = require('./processQueue')
2525
const { RealtimeClientConnection } = require('./realtimeClientConnection')
2626
const { UpdateDirtyNoteJob } = require('./realtimeUpdateDirtyNoteJob')
2727
const { CleanDanglingUserJob } = require('./realtimeCleanDanglingUserJob')
28+
const { SaveRevisionJob } = require('./realtimeSaveRevisionJob')
2829

2930
// public
3031
const realtime = {
@@ -38,6 +39,11 @@ const realtime = {
3839
maintenance: true
3940
}
4041

42+
const disconnectProcessQueue = new ProcessQueue(2000, 500)
43+
const updateDirtyNoteJob = new UpdateDirtyNoteJob(realtime)
44+
const cleanDanglingUserJob = new CleanDanglingUserJob(realtime)
45+
const saveRevisionJob = new SaveRevisionJob(realtime)
46+
4147
function onAuthorizeSuccess (data, accept) {
4248
accept()
4349
}
@@ -88,11 +94,10 @@ function emitCheck (note) {
8894
var users = {}
8995
var notes = {}
9096

91-
const disconnectProcessQueue = new ProcessQueue(2000, 500)
9297
disconnectProcessQueue.start()
93-
94-
const updateDirtyNoteJob = new UpdateDirtyNoteJob(realtime)
95-
updateDirtyNoteJob.start(realtime)
98+
updateDirtyNoteJob.start()
99+
cleanDanglingUserJob.start()
100+
saveRevisionJob.start()
96101

97102
function disconnectSocketOnNote (note) {
98103
note.socks.forEach((sock) => {
@@ -157,28 +162,14 @@ function finishUpdateNote (note, _note, callback) {
157162
lastchangeAt: Date.now()
158163
}
159164
_note.update(values).then(function (_note) {
160-
saverSleep = false
165+
saveRevisionJob.setSaverSleep(false)
161166
return callback(null, _note)
162167
}).catch(function (err) {
163168
logger.error(err)
164169
return callback(err, null)
165170
})
166171
}
167172

168-
const cleanDanglingUserJob = new CleanDanglingUserJob(realtime)
169-
cleanDanglingUserJob.start()
170-
171-
var saverSleep = false
172-
// save note revision in interval
173-
setInterval(function () {
174-
if (saverSleep) return
175-
models.Revision.saveAllNotesRevision(function (err, notes) {
176-
if (err) return logger.error('revision saver failed: ' + err)
177-
if (notes && notes.length <= 0) {
178-
saverSleep = true
179-
}
180-
})
181-
}, 5 * 60 * 1000) // 5 mins
182173

183174
function getStatus (callback) {
184175
models.Note.count().then(function (notecount) {
@@ -806,3 +797,4 @@ exports.getUserPool = getUserPool
806797
exports.disconnectProcessQueue = disconnectProcessQueue
807798
exports.notes = notes
808799
exports.users = users
800+
exports.saveRevisionJob = saveRevisionJob

lib/realtimeSaveRevisionJob.js

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
'use strict'
2+
3+
const models = require('./models')
4+
const logger = require('./logger')
5+
6+
/**
7+
* clean when user not in any rooms or user not in connected list
8+
*/
9+
class SaveRevisionJob {
10+
constructor (realtime) {
11+
this.realtime = realtime
12+
this.saverSleep = false
13+
}
14+
15+
start () {
16+
if (this.timer) return
17+
this.timer = setInterval(this.saveRevision.bind(this), 5 * 60 * 1000)
18+
}
19+
20+
stop () {
21+
if (!this.timer) return
22+
clearInterval(this.timer)
23+
this.timer = undefined
24+
}
25+
26+
saveRevision () {
27+
if (this.getSaverSleep()) return
28+
models.Revision.saveAllNotesRevision((err, notes) => {
29+
if (err) return logger.error('revision saver failed: ' + err)
30+
if (notes && notes.length <= 0) {
31+
this.setSaverSleep(true)
32+
}
33+
})
34+
}
35+
36+
getSaverSleep () {
37+
return this.saverSleep
38+
}
39+
40+
setSaverSleep (val) {
41+
this.saverSleep = val
42+
}
43+
}
44+
45+
exports.SaveRevisionJob = SaveRevisionJob

test/realtime/cleanDanglingUser.test.js

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
const assert = require('assert')
55
const mock = require('mock-require')
66
const sinon = require('sinon')
7-
const {removeModuleFromRequireCache, makeMockSocket} = require('./utils')
7+
const { removeModuleFromRequireCache, makeMockSocket } = require('./utils')
88

99
describe('cleanDanglingUser', function () {
1010
let clock
@@ -25,7 +25,8 @@ describe('cleanDanglingUser', function () {
2525
mock('../../lib/config', {
2626
debug: true
2727
})
28-
mock('../../lib/realtimeUpdateDirtyNoteJob', require('../testDoubles/realtimeUpdateDirtyNoteJobStub'))
28+
mock('../../lib/realtimeUpdateDirtyNoteJob', require('../testDoubles/realtimeJobStub'))
29+
mock('../../lib/realtimeSaveRevisionJob', require('../testDoubles/realtimeJobStub'))
2930
})
3031

3132
afterEach(() => {
@@ -35,7 +36,7 @@ describe('cleanDanglingUser', function () {
3536
sinon.restore()
3637
})
3738

38-
it('should ', (done) => {
39+
it('should call queueForDisconnectSpy when user is dangling', (done) => {
3940
const realtime = require('../../lib/realtime')
4041
const queueForDisconnectSpy = sinon.spy(realtime, 'queueForDisconnect')
4142
realtime.io = {

test/realtime/disconnect-process.test.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ describe('realtime#disconnect', function () {
6161

6262
afterEach(() => {
6363
removeModuleFromRequireCache('../../lib/realtime')
64+
mock.stopAll()
6465
sinon.restore()
6566
})
6667

test/realtime/saveRevisionJob.test.js

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
/* eslint-env node, mocha */
2+
'use strict'
3+
4+
const assert = require('assert')
5+
const mock = require('mock-require')
6+
const sinon = require('sinon')
7+
const { removeModuleFromRequireCache, removeLibModuleCache } = require('./utils')
8+
9+
describe('save revision job', function () {
10+
let clock
11+
let mockModels
12+
let realtime
13+
beforeEach(() => {
14+
removeLibModuleCache()
15+
mockModels = {
16+
Revision: {
17+
saveAllNotesRevision: sinon.stub()
18+
}
19+
}
20+
clock = sinon.useFakeTimers()
21+
mock('../../lib/processQueue', require('../testDoubles/ProcessQueueFake'))
22+
mock('../../lib/logger', {
23+
error: () => {},
24+
info: () => {}
25+
})
26+
mock('../../lib/history', {})
27+
mock('../../lib/models', mockModels)
28+
mock('../../lib/config', {
29+
debug: true
30+
})
31+
mock('../../lib/realtimeUpdateDirtyNoteJob', require('../testDoubles/realtimeJobStub'))
32+
mock('../../lib/realtimeCleanDanglingUserJob', require('../testDoubles/realtimeJobStub'))
33+
})
34+
35+
afterEach(() => {
36+
clock.restore()
37+
removeModuleFromRequireCache('../../lib/realtime')
38+
removeModuleFromRequireCache('../../lib/realtimeSaveRevisionJob')
39+
mock.stopAll()
40+
sinon.restore()
41+
})
42+
43+
it('should execute save revision job every 5 min', (done) => {
44+
mockModels.Revision.saveAllNotesRevision.callsFake((callback) => {
45+
callback(null, [])
46+
})
47+
realtime = require('../../lib/realtime')
48+
clock.tick(5 * 60 * 1000)
49+
clock.restore()
50+
setTimeout(() => {
51+
assert(mockModels.Revision.saveAllNotesRevision.called)
52+
assert(realtime.saveRevisionJob.getSaverSleep() === true)
53+
done()
54+
}, 50)
55+
})
56+
57+
it('should not set saverSleep when more than 1 note save revision', (done) => {
58+
mockModels.Revision.saveAllNotesRevision.callsFake((callback) => {
59+
callback(null, [1])
60+
})
61+
realtime = require('../../lib/realtime')
62+
clock.tick(5 * 60 * 1000)
63+
clock.restore()
64+
setTimeout(() => {
65+
assert(mockModels.Revision.saveAllNotesRevision.called)
66+
assert(realtime.saveRevisionJob.getSaverSleep() === false)
67+
done()
68+
}, 50)
69+
})
70+
})

test/realtime/utils.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
'use strict'
22

33
const sinon = require('sinon')
4+
const path = require('path')
45

56
function makeMockSocket (headers, query) {
67
const broadCastChannelCache = {}
@@ -32,6 +33,15 @@ function makeMockSocket (headers, query) {
3233
function removeModuleFromRequireCache (modulePath) {
3334
delete require.cache[require.resolve(modulePath)]
3435
}
36+
function removeLibModuleCache () {
37+
const libPath = path.resolve(path.join(__dirname, '../../lib'))
38+
Object.keys(require.cache).forEach(key => {
39+
if (key.startsWith(libPath)) {
40+
delete require.cache[require.resolve(key)]
41+
}
42+
})
43+
}
3544

3645
exports.makeMockSocket = makeMockSocket
3746
exports.removeModuleFromRequireCache = removeModuleFromRequireCache
47+
exports.removeLibModuleCache = removeLibModuleCache

test/testDoubles/realtimeJobStub.js

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
'use strict'
2+
3+
class realtimeJobStub {
4+
start() {
5+
}
6+
7+
stop() {
8+
}
9+
}
10+
11+
exports.realtimeJobStub = realtimeJobStub
12+
exports.UpdateDirtyNoteJob = realtimeJobStub
13+
exports.CleanDanglingUserJob = realtimeJobStub
14+
exports.SaveRevisionJob = realtimeJobStub

test/testDoubles/realtimeUpdateDirtyNoteJobStub.js

Lines changed: 0 additions & 12 deletions
This file was deleted.

0 commit comments

Comments
 (0)