mirror of
https://github.com/overleaf/overleaf.git
synced 2024-11-21 20:47:08 -05:00
Merge pull request #16590 from overleaf/jpa-redis-lock-60s
[server-ce] increase the doc lock TTL from 30s to 60s GitOrigin-RevId: 468f7483cc6a80e8034e3cc8071b674123985deb
This commit is contained in:
parent
113fea67fc
commit
8bc44141be
5 changed files with 81 additions and 7 deletions
|
@ -15,10 +15,11 @@ const UNLOCK_SCRIPT =
|
||||||
|
|
||||||
module.exports = class RedisLocker {
|
module.exports = class RedisLocker {
|
||||||
/**
|
/**
|
||||||
* @param rclient initialized ioredis client
|
* @param {import('ioredis')} rclient initialized ioredis client
|
||||||
* @param getKey compose the redis key based on the passed id
|
* @param {function(string): string} getKey compose the redis key based on the passed id
|
||||||
* @param wrapTimeoutError assign the id to a designated field on the error
|
* @param {function(Error, string): Error} wrapTimeoutError assign the id to a designated field on the error
|
||||||
* @param metricsPrefix prefix all the metrics with the given prefix
|
* @param {string} metricsPrefix prefix all the metrics with the given prefix
|
||||||
|
* @param {number} lockTTLSeconds
|
||||||
*
|
*
|
||||||
* @example ```
|
* @example ```
|
||||||
* const lock = new RedisLocker({
|
* const lock = new RedisLocker({
|
||||||
|
@ -35,7 +36,22 @@ module.exports = class RedisLocker {
|
||||||
* }
|
* }
|
||||||
* ```
|
* ```
|
||||||
*/
|
*/
|
||||||
constructor({ rclient, getKey, wrapTimeoutError, metricsPrefix }) {
|
constructor({
|
||||||
|
rclient,
|
||||||
|
getKey,
|
||||||
|
wrapTimeoutError,
|
||||||
|
metricsPrefix,
|
||||||
|
lockTTLSeconds = 30,
|
||||||
|
}) {
|
||||||
|
if (
|
||||||
|
typeof lockTTLSeconds !== 'number' ||
|
||||||
|
lockTTLSeconds < 30 ||
|
||||||
|
lockTTLSeconds >= 1000
|
||||||
|
) {
|
||||||
|
// set upper limit to 1000s to detect wrong units
|
||||||
|
throw new Error('redis lock TTL must be at least 30s and below 1000s')
|
||||||
|
}
|
||||||
|
|
||||||
this.rclient = rclient
|
this.rclient = rclient
|
||||||
this.getKey = getKey
|
this.getKey = getKey
|
||||||
this.wrapTimeoutError = wrapTimeoutError
|
this.wrapTimeoutError = wrapTimeoutError
|
||||||
|
@ -44,7 +60,7 @@ module.exports = class RedisLocker {
|
||||||
this.LOCK_TEST_INTERVAL = 50 // 50ms between each test of the lock
|
this.LOCK_TEST_INTERVAL = 50 // 50ms between each test of the lock
|
||||||
this.MAX_TEST_INTERVAL = 1000 // back off to 1s between each test of the lock
|
this.MAX_TEST_INTERVAL = 1000 // back off to 1s between each test of the lock
|
||||||
this.MAX_LOCK_WAIT_TIME = 10000 // 10s maximum time to spend trying to get the lock
|
this.MAX_LOCK_WAIT_TIME = 10000 // 10s maximum time to spend trying to get the lock
|
||||||
this.LOCK_TTL = 30 // seconds. Time until lock auto expires in redis.
|
this.LOCK_TTL = lockTTLSeconds // seconds. Time until lock auto expires in redis.
|
||||||
|
|
||||||
// read-only copy for unit tests
|
// read-only copy for unit tests
|
||||||
this.unlockScript = UNLOCK_SCRIPT
|
this.unlockScript = UNLOCK_SCRIPT
|
||||||
|
|
|
@ -10,6 +10,7 @@ const assert = require('assert')
|
||||||
const path = require('path')
|
const path = require('path')
|
||||||
const sinon = require('sinon')
|
const sinon = require('sinon')
|
||||||
const modulePath = path.join(__dirname, './../../../index.js')
|
const modulePath = path.join(__dirname, './../../../index.js')
|
||||||
|
const redisLockerModulePath = path.join(__dirname, './../../../RedisLocker.js')
|
||||||
const { expect } = require('chai')
|
const { expect } = require('chai')
|
||||||
|
|
||||||
describe('index', function () {
|
describe('index', function () {
|
||||||
|
@ -53,9 +54,58 @@ describe('index', function () {
|
||||||
},
|
},
|
||||||
globals: {
|
globals: {
|
||||||
process,
|
process,
|
||||||
|
Buffer,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
return (this.auth_pass = '1234 pass')
|
this.auth_pass = '1234 pass'
|
||||||
|
|
||||||
|
this.RedisLocker = SandboxedModule.require(redisLockerModulePath, {
|
||||||
|
requires: {
|
||||||
|
'@overleaf/metrics': {
|
||||||
|
inc() {},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
globals: {
|
||||||
|
process,
|
||||||
|
Math,
|
||||||
|
Buffer,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('lock TTL', function () {
|
||||||
|
it('should throw an error when creating a client with wrong type', function () {
|
||||||
|
const createNewRedisLock = () => {
|
||||||
|
return new this.RedisLocker({
|
||||||
|
lockTTLSeconds: '60',
|
||||||
|
})
|
||||||
|
}
|
||||||
|
expect(createNewRedisLock).to.throw(
|
||||||
|
'redis lock TTL must be at least 30s and below 1000s'
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should throw an error when creating a client with small TTL', function () {
|
||||||
|
const createNewRedisLock = () => {
|
||||||
|
return new this.RedisLocker({
|
||||||
|
lockTTLSeconds: 1,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
expect(createNewRedisLock).to.throw(
|
||||||
|
'redis lock TTL must be at least 30s and below 1000s'
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should throw an error when creating a client with huge TTL', function () {
|
||||||
|
const createNewRedisLock = () => {
|
||||||
|
return new this.RedisLocker({
|
||||||
|
lockTTLSeconds: 30_000,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
expect(createNewRedisLock).to.throw(
|
||||||
|
'redis lock TTL must be at least 30s and below 1000s'
|
||||||
|
)
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('redis-sentinel', function () {
|
describe('redis-sentinel', function () {
|
||||||
|
|
|
@ -235,6 +235,11 @@ const settings = {
|
||||||
10
|
10
|
||||||
),
|
),
|
||||||
|
|
||||||
|
redisLockTTLSeconds: parseInt(
|
||||||
|
process.env.SHARELATEX_REDIS_LOCK_TTL_SECONDS || '60',
|
||||||
|
10
|
||||||
|
),
|
||||||
|
|
||||||
i18n: {
|
i18n: {
|
||||||
subdomainLang: {
|
subdomainLang: {
|
||||||
www: {
|
www: {
|
||||||
|
|
|
@ -14,4 +14,5 @@ module.exports = new RedisLocker({
|
||||||
return err
|
return err
|
||||||
},
|
},
|
||||||
metricsPrefix: 'doc',
|
metricsPrefix: 'doc',
|
||||||
|
lockTTLSeconds: Settings.redisLockTTLSeconds,
|
||||||
})
|
})
|
||||||
|
|
|
@ -150,6 +150,8 @@ module.exports = {
|
||||||
|
|
||||||
dispatcherCount: parseInt(process.env.DISPATCHER_COUNT || 10, 10),
|
dispatcherCount: parseInt(process.env.DISPATCHER_COUNT || 10, 10),
|
||||||
|
|
||||||
|
redisLockTTLSeconds: 30,
|
||||||
|
|
||||||
mongo: {
|
mongo: {
|
||||||
url:
|
url:
|
||||||
process.env.MONGO_CONNECTION_STRING ||
|
process.env.MONGO_CONNECTION_STRING ||
|
||||||
|
|
Loading…
Reference in a new issue