Merge pull request #2860 from overleaf/jpa-socket-io-v2-percentage-rollout

[misc] prepare for a percentage roll-out of socket.io v2

GitOrigin-RevId: 792eddeb4a9b41aded67fee13faa949122cd0faf
This commit is contained in:
Jakob Ackermann 2020-05-26 12:32:05 +02:00 committed by Copybot
parent deeaed66f9
commit 419100d167
3 changed files with 168 additions and 2 deletions

View file

@ -7,6 +7,7 @@ const fs = require('fs')
const crypto = require('crypto')
const async = require('async')
const logger = require('logger-sharelatex')
const { ObjectId } = require('../../infrastructure/mongojs')
const ProjectDeleter = require('./ProjectDeleter')
const ProjectDuplicator = require('./ProjectDuplicator')
const ProjectCreationHandler = require('./ProjectCreationHandler')
@ -722,6 +723,15 @@ const ProjectController = {
if (user.betaProgram && Settings.wsUrlBeta !== undefined) {
wsUrl = Settings.wsUrlBeta
metricName += '-beta'
} else if (
Settings.wsUrlV2 &&
Settings.wsUrlV2Percentage > 0 &&
(ObjectId(projectId).getTimestamp() / 1000) %
100 <
Settings.wsUrlV2Percentage
) {
wsUrl = Settings.wsUrlV2
metricName += '-v2'
}
if (req.query && req.query.ws === 'fallback') {
// `?ws=fallback` will connect to the bare origin, and ignore

View file

@ -196,8 +196,11 @@ module.exports = settings =
# Optional separate location for websocket connections, if unset defaults to siteUrl.
wsUrl: process.env['WEBSOCKET_URL']
wsUrlV2: process.env['WEBSOCKET_URL_V2']
wsUrlBeta: process.env['WEBSOCKET_URL_BETA']
wsUrlV2Percentage: parseInt(process.env['WEBSOCKET_URL_V2_PERCENTAGE'] || '0', 10)
# cookie domain
# use full domain for cookies to only be accessible from that domain,
# replace subdomain with dot to have them accessible on all subdomains

View file

@ -1082,7 +1082,7 @@ describe('ProjectController', function() {
this.ProjectController.loadEditor(this.req, this.res)
})
}
function checkWsFallback(isBeta) {
function checkWsFallback(isBeta, isV2) {
describe('with ws=fallback', function() {
beforeEach(function() {
this.req.query = {}
@ -1096,7 +1096,9 @@ describe('ProjectController', function() {
this.ProjectController.loadEditor(this.req, this.res)
})
checkLoadEditorWsMetric(
`load-editor-ws${isBeta ? '-beta' : ''}-fallback`
`load-editor-ws${isBeta ? '-beta' : ''}${
isV2 ? '-v2' : ''
}-fallback`
)
})
}
@ -1145,6 +1147,157 @@ describe('ProjectController', function() {
checkWsFallback(true)
})
})
describe('v2-rollout', function() {
beforeEach(function() {
this.settings.wsUrlBeta = '/beta.socket.io'
this.settings.wsUrlV2 = '/socket.io.v2'
})
function checkNonMatch() {
it('should set the normal custom wsUrl', function(done) {
this.res.render = (pageName, opts) => {
opts.wsUrl.should.equal('/other.socket.io')
done()
}
this.ProjectController.loadEditor(this.req, this.res)
})
checkLoadEditorWsMetric('load-editor-ws')
checkWsFallback(false)
}
function checkMatch() {
it('should set the v2 wsUrl', function(done) {
this.res.render = (pageName, opts) => {
opts.wsUrl.should.equal('/socket.io.v2')
done()
}
this.ProjectController.loadEditor(this.req, this.res)
})
checkLoadEditorWsMetric('load-editor-ws-v2')
checkWsFallback(false, true)
}
function checkForBetaUser() {
describe('for a beta user', function() {
beforeEach(function() {
this.user.betaProgram = true
})
it('should set the beta wsUrl', function(done) {
this.res.render = (pageName, opts) => {
opts.wsUrl.should.equal('/beta.socket.io')
done()
}
this.ProjectController.loadEditor(this.req, this.res)
})
checkLoadEditorWsMetric('load-editor-ws-beta')
checkWsFallback(true)
})
}
describe('when the roll out percentage is 0', function() {
beforeEach(function() {
this.settings.wsUrlV2Percentage = 0
})
describe('when the projectId does not match (0)', function() {
beforeEach(function() {
this.req.params.Project_id = ObjectId.createFromTime(0)
})
checkNonMatch()
})
describe('when the projectId does not match (42)', function() {
beforeEach(function() {
this.req.params.Project_id = ObjectId.createFromTime(42)
})
checkNonMatch()
})
checkForBetaUser()
})
describe('when the roll out percentage is 1', function() {
beforeEach(function() {
this.settings.wsUrlV2Percentage = 1
})
describe('when the projectId matches (0)', function() {
beforeEach(function() {
this.req.params.Project_id = ObjectId.createFromTime(0)
})
checkMatch()
checkForBetaUser()
})
describe('when the projectId does not match (1)', function() {
beforeEach(function() {
this.req.params.Project_id = ObjectId.createFromTime(1)
})
checkNonMatch()
checkForBetaUser()
})
describe('when the projectId does not match (42)', function() {
beforeEach(function() {
this.req.params.Project_id = ObjectId.createFromTime(42)
})
checkNonMatch()
})
})
describe('when the roll out percentage is 10', function() {
beforeEach(function() {
this.settings.wsUrlV2Percentage = 10
})
describe('when the projectId matches (0)', function() {
beforeEach(function() {
this.req.params.Project_id = ObjectId.createFromTime(0)
})
checkMatch()
})
describe('when the projectId matches (9)', function() {
beforeEach(function() {
this.req.params.Project_id = ObjectId.createFromTime(9)
})
checkMatch()
checkForBetaUser()
})
describe('when the projectId does not match (10)', function() {
beforeEach(function() {
this.req.params.Project_id = ObjectId.createFromTime(10)
})
checkNonMatch()
})
describe('when the projectId does not match (42)', function() {
beforeEach(function() {
this.req.params.Project_id = ObjectId.createFromTime(42)
})
checkNonMatch()
checkForBetaUser()
})
})
describe('when the roll out percentage is 100', function() {
beforeEach(function() {
this.settings.wsUrlV2Percentage = 100
})
describe('when the projectId matches (0)', function() {
beforeEach(function() {
this.req.params.Project_id = ObjectId.createFromTime(0)
})
checkMatch()
checkForBetaUser()
})
describe('when the projectId matches (10)', function() {
beforeEach(function() {
this.req.params.Project_id = ObjectId.createFromTime(10)
})
checkMatch()
})
describe('when the projectId matches (42)', function() {
beforeEach(function() {
this.req.params.Project_id = ObjectId.createFromTime(42)
})
checkMatch()
})
describe('when the projectId matches (99)', function() {
beforeEach(function() {
this.req.params.Project_id = ObjectId.createFromTime(99)
})
checkMatch()
})
})
})
})
})