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 // Handle the last known state (if any) as an incoming update
// This triggers the main update pipeline and enables centralized update handling // 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 // Allow the ServerRegistration to bind any DOM events with app instance context
serverRegistration.initEventListeners() serverRegistration.initEventListeners()

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

@ -79,27 +79,30 @@ export class SocketManager {
break break
case 'updateServer': { case 'updateServers': {
// The backend may send "update" events prior to receiving all "add" events for (let serverId = 0; serverId < payload.updates.length; serverId++) {
// A server has only been added once it's ServerRegistration is defined // The backend may send "update" events prior to receiving all "add" events
// Checking undefined protects from this race condition // A server has only been added once it's ServerRegistration is defined
const serverRegistration = this._app.serverRegistry.getServerRegistration(payload.serverId) // Checking undefined protects from this race condition
const serverRegistration = this._app.serverRegistry.getServerRegistration(serverId)
const serverUpdate = payload.updates[serverId]
if (serverRegistration) { 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 // Use update payloads to conditionally append data to graph
// Skip any incoming updates if the graph is disabled // 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 // 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) this._app.graphDisplayManager.addGraphPoint(serverRegistration.serverId, payload.timestamp, playerCount)
// Only redraw the graph if not mutating hidden data // Only redraw the graph if not mutating hidden data
if (serverRegistration.isVisible) { if (serverRegistration.isVisible) {
this._app.graphDisplayManager.requestRedraw() this._app.graphDisplayManager.requestRedraw()
}
} }
} }
break break

@ -97,6 +97,40 @@ class PingController {
} }
pingAll = () => { 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) { for (const serverRegistration of this._app.serverRegistrations) {
const version = serverRegistration.getNextProtocolVersion() const version = serverRegistration.getNextProtocolVersion()
@ -105,36 +139,18 @@ class PingController {
logger.log('error', 'Failed to ping %s: %s', serverRegistration.data.ip, err.message) 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) }, 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 module.exports = PingController

@ -14,12 +14,30 @@ class ServerRegistration {
this._pingHistory = [] this._pingHistory = []
} }
getUpdate (timestamp, resp, err, version, updateHistoryGraph) { handlePing (timestamp, resp, err, version) {
const update = { // Store into in-memory ping data
serverId: this.serverId, this.addPing(timestamp, resp)
timestamp: timestamp
// 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) {
if (resp.version && this.updateProtocolVersionCompat(resp.version, version.protocolId, version.protocolIndex)) { if (resp.version && this.updateProtocolVersionCompat(resp.version, version.protocolId, version.protocolIndex)) {
// Append an updated version listing // Append an updated version listing