mirror of
https://github.com/codeninjasllc/codecombat.git
synced 2025-03-14 07:00:01 -04:00
Improve server caching and ladder view refresh performance
This commit is contained in:
parent
b21c20c08d
commit
77731dad84
10 changed files with 48 additions and 37 deletions
|
@ -149,6 +149,9 @@ module.exports = class LadderTabView extends CocoView
|
|||
# LADDER LOADING
|
||||
|
||||
refreshLadder: ->
|
||||
# Only do this so often if not in a league; servers cache a lot of this data for a few minutes anyway.
|
||||
return if not @options.league and (new Date() - 2 * 60 * 1000 < @lastRefreshTime)
|
||||
@lastRefreshTime = new Date()
|
||||
@supermodel.resetProgress()
|
||||
@ladderLimit ?= parseInt @getQueryVariable('top_players', if @options.league then 100 else 20)
|
||||
for team in @teams
|
||||
|
@ -171,7 +174,7 @@ module.exports = class LadderTabView extends CocoView
|
|||
level = "#{@level.get('original')}.#{@level.get('version').major}"
|
||||
url = "/db/level/#{level}/histogram_data?team=#{team.name.toLowerCase()}"
|
||||
url += '&leagues.leagueID=' + @options.league.id if @options.league
|
||||
$.get url, {cache: false}, (data) -> histogramData = data
|
||||
$.get url, (data) -> histogramData = data
|
||||
).then =>
|
||||
@generateHistogram(histogramWrapper, histogramData, team.name.toLowerCase()) unless @destroyed
|
||||
|
||||
|
@ -311,6 +314,7 @@ module.exports = class LadderTabView extends CocoView
|
|||
onLoadMoreLadderEntries: (e) ->
|
||||
@ladderLimit ?= 100
|
||||
@ladderLimit += 100
|
||||
@lastRefreshTime = null
|
||||
@refreshLadder()
|
||||
|
||||
module.exports.LeaderboardData = LeaderboardData = class LeaderboardData extends CocoClass
|
||||
|
|
|
@ -92,7 +92,14 @@ module.exports = class LadderView extends RootView
|
|||
@insertSubView(@ladderTab = new LadderTabView({league: @league}, @level, @sessions))
|
||||
@insertSubView(@myMatchesTab = new MyMatchesTabView({league: @league}, @level, @sessions))
|
||||
@insertSubView(@simulateTab = new SimulateTabView(league: @league))
|
||||
@refreshInterval = setInterval(@fetchSessionsAndRefreshViews.bind(@), 60 * 1000)
|
||||
highLoad = true
|
||||
@refreshDelay = switch
|
||||
when not application.isProduction() then 10 # Refresh very quickly in develompent.
|
||||
when @league then 20 # Refresh quickly when looking at a league ladder.
|
||||
when not highLoad then 30 # Refresh slowly when in production.
|
||||
when not me.isAnonymous() then 60 # Refresh even more slowly during HoC scaling.
|
||||
else 300 # Refresh super slowly if anonymous during HoC scaling.
|
||||
@refreshInterval = setInterval(@fetchSessionsAndRefreshViews.bind(@), @refreshDelay * 1000)
|
||||
hash = document.location.hash[1..] if document.location.hash
|
||||
if hash and not (hash in ['my-matches', 'simulate', 'ladder', 'prizes', 'rules', 'winners'])
|
||||
@showPlayModal(hash) if @sessions.loaded
|
||||
|
@ -105,7 +112,7 @@ module.exports = class LadderView extends RootView
|
|||
return if @destroyed or application.userIsIdle
|
||||
@lastRefreshTime = new Date()
|
||||
@ladderTab.refreshLadder()
|
||||
@myMatchesTab.refreshMatches()
|
||||
@myMatchesTab.refreshMatches @refreshDelay
|
||||
@simulateTab.refresh()
|
||||
|
||||
onIdleChanged: (e) ->
|
||||
|
|
|
@ -14,9 +14,9 @@ module.exports = class MyMatchesTabView extends CocoView
|
|||
super(options)
|
||||
@nameMap = {}
|
||||
@previouslyRankingTeams = {}
|
||||
@refreshMatches()
|
||||
@refreshMatches 20
|
||||
|
||||
refreshMatches: ->
|
||||
refreshMatches: (@refreshDelay) ->
|
||||
@teams = teamDataFromLevel @level
|
||||
@loadNames()
|
||||
|
||||
|
@ -74,7 +74,7 @@ module.exports = class MyMatchesTabView extends CocoView
|
|||
state = 'win'
|
||||
state = 'loss' if match.metrics.rank > opponent.metrics.rank
|
||||
state = 'tie' if match.metrics.rank is opponent.metrics.rank
|
||||
fresh = match.date > (new Date(new Date() - 20 * 1000)).toISOString()
|
||||
fresh = match.date > (new Date(new Date() - @refreshDelay * 1000)).toISOString()
|
||||
if fresh
|
||||
@playSound 'chat_received'
|
||||
{
|
||||
|
|
|
@ -74,6 +74,7 @@ module.exports = class SimulateTabView extends CocoView
|
|||
@simulator.fetchAndSimulateTask()
|
||||
|
||||
refresh: ->
|
||||
return # Queue-based scoring is currently not active anyway, so don't keep checking this until we fix it.
|
||||
success = (numberOfGamesInQueue) ->
|
||||
$('#games-in-queue').text numberOfGamesInQueue
|
||||
$.ajax '/queue/messagesInQueueCount', cache: false, success: success
|
||||
|
|
|
@ -69,7 +69,7 @@
|
|||
"moment": "~2.5.0",
|
||||
"mongodb": "^2.0.28",
|
||||
"mongoose": "3.8.x",
|
||||
"mongoose-cache": "~0.1.4",
|
||||
"mongoose-cache": "https://github.com/nwinter/mongoose-cache/tarball/master",
|
||||
"node-force-domain": "~0.1.0",
|
||||
"node-gyp": "~0.13.0",
|
||||
"node-statsd": "^0.1.1",
|
||||
|
|
|
@ -18,7 +18,8 @@ module.exports.connect = () ->
|
|||
# https://github.com/LearnBoost/mongoose/issues/1910
|
||||
Level = require '../levels/Level'
|
||||
Aggregate = Level.aggregate().constructor
|
||||
mongooseCache.install(mongoose, {max: 200, maxAge: 1 * 60 * 1000, debug: false}, Aggregate)
|
||||
maxAge = (Math.random() * 10 + 10) * 60 * 1000 # Randomize so that each server doesn't refresh cache from db at same times
|
||||
mongooseCache.install(mongoose, {max: 1000, maxAge: maxAge, debug: false}, Aggregate)
|
||||
|
||||
module.exports.generateMongoConnectionString = ->
|
||||
if not testing and config.tokyo
|
||||
|
|
|
@ -208,7 +208,7 @@ LevelHandler = class LevelHandler extends Handler
|
|||
{$match: match}
|
||||
{$project: project}
|
||||
]
|
||||
aggregate.cache() unless league
|
||||
aggregate.cache(10 * 60 * 1000) unless league
|
||||
|
||||
aggregate.exec (err, data) =>
|
||||
if err? then return @sendDatabaseError res, err
|
||||
|
@ -244,7 +244,7 @@ LevelHandler = class LevelHandler extends Handler
|
|||
.limit(req.query.limit)
|
||||
.sort(sortParameters)
|
||||
.select(selectProperties.join ' ')
|
||||
query.cache() if sessionsQueryParameters.totalScore.$lt is 1000000
|
||||
query.cache(5 * 60 * 1000) if sessionsQueryParameters.totalScore.$lt is 1000000
|
||||
|
||||
query.exec (err, resultSessions) =>
|
||||
return @sendDatabaseError(res, err) if err
|
||||
|
@ -302,7 +302,7 @@ LevelHandler = class LevelHandler extends Handler
|
|||
.find(level: leaderboardOptions.find.level, creator: {$in: @ladderBenchmarkAIs})
|
||||
.sort(leaderboardOptions.sort)
|
||||
.select(leaderboardOptions.select.join ' ')
|
||||
.cache() # TODO: How long does this cache? We will probably want these to be pretty long.
|
||||
.cache(30 * 60 * 1000)
|
||||
.exec (err, aiSessions) ->
|
||||
return cb err if err
|
||||
matchingAISessions = _.filter aiSessions, (aiSession) ->
|
||||
|
@ -350,9 +350,9 @@ LevelHandler = class LevelHandler extends Handler
|
|||
findParameters['slug'] = slugOrID
|
||||
selectString = 'original version'
|
||||
query = Level.findOne(findParameters)
|
||||
.select(selectString)
|
||||
.lean()
|
||||
.cache()
|
||||
.select(selectString)
|
||||
.lean()
|
||||
.cache(60 * 60 * 1000)
|
||||
|
||||
query.exec (err, level) =>
|
||||
return @sendDatabaseError(res, err) if err
|
||||
|
@ -364,27 +364,25 @@ LevelHandler = class LevelHandler extends Handler
|
|||
majorVersion: level.version.major
|
||||
submitted: true
|
||||
|
||||
query = Session.find(sessionsQueryParameters).distinct('team').cache()
|
||||
query.exec (err, teams) =>
|
||||
return @sendDatabaseError res, err if err? or not teams
|
||||
findTop20Players = (sessionQueryParams, team, cb) ->
|
||||
sessionQueryParams['team'] = team
|
||||
aggregate = Session.aggregate [
|
||||
{$match: sessionQueryParams}
|
||||
{$sort: {'totalScore': -1}}
|
||||
{$limit: 20}
|
||||
{$project: {'totalScore': 1}}
|
||||
]
|
||||
aggregate.cache()
|
||||
aggregate.exec cb
|
||||
teams = ['humans', 'ogres']
|
||||
findTop20Players = (sessionQueryParams, team, cb) ->
|
||||
sessionQueryParams['team'] = team
|
||||
aggregate = Session.aggregate [
|
||||
{$match: sessionQueryParams}
|
||||
{$sort: {'totalScore': -1}}
|
||||
{$limit: 20}
|
||||
{$project: {'totalScore': 1}}
|
||||
]
|
||||
aggregate.cache(3 * 60 * 1000)
|
||||
aggregate.exec cb
|
||||
|
||||
async.map teams, findTop20Players.bind(@, sessionsQueryParameters), (err, map) =>
|
||||
if err? then return @sendDatabaseError(res, err)
|
||||
sessions = []
|
||||
for mapItem in map
|
||||
sessions.push _.sample(mapItem)
|
||||
if map.length != 2 then return @sendDatabaseError res, 'There aren\'t sessions of 2 teams, so cannot choose random opponents!'
|
||||
@sendSuccess res, sessions
|
||||
async.map teams, findTop20Players.bind(@, sessionsQueryParameters), (err, map) =>
|
||||
if err? then return @sendDatabaseError(res, err)
|
||||
sessions = []
|
||||
for mapItem in map
|
||||
sessions.push _.sample(mapItem)
|
||||
if map.length != 2 then return @sendDatabaseError res, 'There aren\'t sessions of 2 teams, so cannot choose random opponents!'
|
||||
@sendSuccess res, sessions
|
||||
|
||||
getFeedback: (req, res, levelID) ->
|
||||
return @sendNotFoundError(res) unless req.user
|
||||
|
|
|
@ -71,7 +71,7 @@ ThangTypeHandler = class ThangTypeHandler extends Handler
|
|||
if limit? and limit < 1000
|
||||
q.limit(limit)
|
||||
|
||||
q.cache()
|
||||
q.cache(10 * 60 * 1000)
|
||||
|
||||
q.exec (err, documents) =>
|
||||
return @sendDatabaseError(res, err) if err
|
||||
|
|
|
@ -55,7 +55,7 @@ class UserCodeProblemHandler extends Handler
|
|||
group = {"$group": {"_id": {"errMessage": "$errMessageNoLineInfo", "errHint": "$errHint", "language": "$language", "levelID": "$levelID"}, "count": {"$sum": 1}}}
|
||||
sort = { $sort : { "_id.levelID": 1, count : -1, "_id.language": 1 } }
|
||||
query = UserCodeProblem.aggregate match, limit, group, sort
|
||||
query.cache()
|
||||
query.cache(30 * 60 * 1000)
|
||||
|
||||
query.exec (err, data) =>
|
||||
if err? then return @sendDatabaseError res, err
|
||||
|
|
|
@ -199,7 +199,7 @@ UserHandler = class UserHandler extends Handler
|
|||
getSimulatorLeaderboard: (req, res) ->
|
||||
queryParameters = @getSimulatorLeaderboardQueryParameters(req)
|
||||
leaderboardQuery = User.find(queryParameters.query).select('name simulatedBy simulatedFor').sort({'simulatedBy': queryParameters.sortOrder}).limit(queryParameters.limit)
|
||||
leaderboardQuery.cache() if req.query.scoreOffset is -1
|
||||
leaderboardQuery.cache(10 * 60 * 1000) if req.query.scoreOffset is -1
|
||||
leaderboardQuery.exec (err, otherUsers) ->
|
||||
otherUsers = _.reject otherUsers, _id: req.user._id if req.query.scoreOffset isnt -1 and req.user
|
||||
otherUsers ?= []
|
||||
|
|
Loading…
Reference in a new issue