work on bulking updateServer payloads and single timestamps

This commit is contained in:
Nick Krecklow 2020-05-08 00:36:15 -05:00
parent a3c88dc0c5
commit 3ddb2c9a08
No known key found for this signature in database
GPG Key ID: 5F149FDE156FFA94
5 changed files with 90 additions and 53 deletions

@ -121,7 +121,7 @@ export class App {
// Handle the last known state (if any) as an incoming update
// This triggers the main update pipeline and enables centralized update handling
serverRegistration.updateServerStatus(latestPing, true, this.publicConfig.minecraftVersions)
serverRegistration.updateServerStatus(latestPing, latestPing.timestamp, true, this.publicConfig.minecraftVersions)
// Allow the ServerRegistration to bind any DOM events with app instance context
serverRegistration.initEventListeners()

@ -113,14 +113,14 @@ export class ServerRegistration {
this._plotInstance = $.plot('#chart_' + this.serverId, [this._graphData], SERVER_GRAPH_OPTIONS)
}
handlePing (payload, pushToGraph) {
handlePing (payload, timestamp, pushToGraph) {
if (payload.result) {
this.playerCount = payload.result.players.online
if (pushToGraph) {
// Only update graph for successful pings
// This intentionally pauses the server graph when pings begin to fail
this._graphData.push([payload.timestamp, this.playerCount])
this._graphData.push([timestamp, this.playerCount])
// Trim graphData to within the max length by shifting out the leading elements
if (this._graphData.length > SERVER_GRAPH_DATA_MAX_LENGTH) {
@ -169,10 +169,10 @@ export class ServerRegistration {
this.lastPeakData = data
}
updateServerStatus (ping, isInitialUpdate, minecraftVersions) {
updateServerStatus (ping, timestamp, isInitialUpdate, minecraftVersions) {
// Only pushToGraph when initialUpdate === false
// Otherwise the ping value is pushed into the graphData when already present
this.handlePing(ping, !isInitialUpdate)
this.handlePing(ping, timestamp, !isInitialUpdate)
if (ping.versions) {
const versionsElement = document.getElementById('version_' + this.serverId)

@ -79,21 +79,23 @@ export class SocketManager {
break
case 'updateServer': {
case 'updateServers': {
for (let serverId = 0; serverId < payload.updates.length; serverId++) {
// The backend may send "update" events prior to receiving all "add" events
// A server has only been added once it's ServerRegistration is defined
// Checking undefined protects from this race condition
const serverRegistration = this._app.serverRegistry.getServerRegistration(payload.serverId)
const serverRegistration = this._app.serverRegistry.getServerRegistration(serverId)
const serverUpdate = payload.updates[serverId]
if (serverRegistration) {
serverRegistration.updateServerStatus(payload, false, this._app.publicConfig.minecraftVersions)
serverRegistration.updateServerStatus(serverUpdate, payload.timestamp, false, this._app.publicConfig.minecraftVersions)
}
// Use update payloads to conditionally append data to graph
// Skip any incoming updates if the graph is disabled
if (payload.updateHistoryGraph && this._app.graphDisplayManager.isVisible) {
if (serverUpdate.updateHistoryGraph && this._app.graphDisplayManager.isVisible) {
// Update may not be successful, safely append 0 points
const playerCount = payload.result ? payload.result.players.online : 0
const playerCount = serverUpdate.result ? serverUpdate.result.players.online : 0
this._app.graphDisplayManager.addGraphPoint(serverRegistration.serverId, payload.timestamp, playerCount)
@ -102,6 +104,7 @@ export class SocketManager {
this._app.graphDisplayManager.requestRedraw()
}
}
}
break
}

@ -97,6 +97,40 @@ class PingController {
}
pingAll = () => {
const timestamp = new Date().getTime()
this.startPingTasks(results => {
const updates = []
for (const serverRegistration of this._app.serverRegistrations) {
const result = results[serverRegistration.serverId]
// Log to database if enabled
if (config.logToDatabase) {
const playerCount = result.resp ? result.resp.players.online : 0
this._app.database.insertPing(serverRegistration.data.ip, timestamp, playerCount)
}
// Generate a combined update payload
// This includes any modified fields and flags used by the frontend
// This will not be cached and can contain live metadata
const update = serverRegistration.handlePing(timestamp, result.resp, result.err, result.version)
updates[serverRegistration.serverId] = update
}
// Send object since updates uses serverIds as keys
// Send a single timestamp entry since it is shared
this._app.server.broadcast(MessageOf('updateServers', {
timestamp,
updates
}))
})
}
startPingTasks = (callback) => {
const results = []
let remainingTasks = this._app.serverRegistrations.length
for (const serverRegistration of this._app.serverRegistrations) {
const version = serverRegistration.getNextProtocolVersion()
@ -105,36 +139,18 @@ class PingController {
logger.log('error', 'Failed to ping %s: %s', serverRegistration.data.ip, err.message)
}
this.handlePing(serverRegistration, resp, err, version)
results[serverRegistration.serverId] = {
resp,
err,
version
}
if (--remainingTasks === 0) {
callback(results)
}
}, version.protocolId)
}
}
handlePing (serverRegistration, resp, err, version) {
const timestamp = new Date().getTime()
serverRegistration.addPing(timestamp, resp)
let updateHistoryGraph = false
if (config.logToDatabase) {
const playerCount = resp ? resp.players.online : 0
// Log to database
this._app.database.insertPing(serverRegistration.data.ip, timestamp, playerCount)
if (serverRegistration.addGraphPoint(resp !== undefined, playerCount, timestamp)) {
updateHistoryGraph = true
}
}
// Generate a combined update payload
// This includes any modified fields and flags used by the frontend
// This will not be cached and can contain live metadata
const updateMessage = serverRegistration.getUpdate(timestamp, resp, err, version, updateHistoryGraph)
this._app.server.broadcast(MessageOf('updateServer', updateMessage))
}
}
module.exports = PingController

@ -14,11 +14,29 @@ class ServerRegistration {
this._pingHistory = []
}
getUpdate (timestamp, resp, err, version, updateHistoryGraph) {
const update = {
serverId: this.serverId,
timestamp: timestamp
handlePing (timestamp, resp, err, version) {
// Store into in-memory ping data
this.addPing(timestamp, resp)
// Only notify the frontend to append to the historical graph
// if both the graphing behavior is enabled and the backend agrees
// that the ping is eligible for addition
let updateHistoryGraph = false
if (config.logToDatabase) {
const playerCount = resp ? resp.players.online : 0
if (this.addGraphPoint(resp !== undefined, playerCount, timestamp)) {
updateHistoryGraph = true
}
}
// Delegate out update payload generation
return this.getUpdate(timestamp, resp, err, version, updateHistoryGraph)
}
getUpdate (timestamp, resp, err, version, updateHistoryGraph) {
const update = {}
if (resp) {
if (resp.version && this.updateProtocolVersionCompat(resp.version, version.protocolId, version.protocolIndex)) {