1
\$\begingroup\$

This question already has an answer here:

im currently writing a simple server for a mobile/web game. In short, players have a number of buildings that will produce several items every x minutes. What i though as a solution its creating a column named "nextProduction" and start a cronjob that will give the items and update that column, then renew the cronjob for the next iteration.

Now i have doubt about it, maybe this solution will be too resource intensive as the number of players increase? Thanks beforehand

\$\endgroup\$

marked as duplicate by Stephane Hockenhull, DMGregory, Tyyppi_77, Jimmy, Alexandre Vaillancourt Nov 20 '17 at 14:47

This question has been asked before and already has an answer. If those answers do not fully address your question, please ask a new question.

1
\$\begingroup\$

TL;DR

I suggest you use lazy evaluation. Skip to 3) to learn more.

1) Don't optimize too early

First we need to define what you mean by "resource intensive". Which resource? CPU? Disk space? I/O? What's the bottleneck?

The usual approach is to build something first, profile it or stress test it until it begins to fail, and then look at which resources got maxed out. If your program reaches 100% CPU usage before it reaches 100% memory usage, then the CPU is the bottleneck - in other words, you are CPU-constrained.

Now, for the game you're describing, I assume the current number of resources for each player will be stored in a database. If so, then database I/O will most likely be your bottleneck, because each run of the updating a row on a database is relatively expensive compared to, say, updating a value in memory.

Updating those cronjobs might also be expensive depending on where they are stored. Crontabs are usually stored on the disk (and disk I/O is expensive) but sometimes they are stored in memory instead. It depends on whether you want persistence.

That being said, "expensive" is relative. Modern servers are fast. Your approach might scale better than you think. If you need to scale it even further, it might be cheaper to pay for extra hardware than to invest the man-hours to optimize it.

2) Suggested improvements

Updating a cronjob and the database on each run is unnecessarily complex. For starters, let's try updating only one thing at a time. Here's your database schema:

resourceAmount INT | productionCooldown INT | lastResourceDrop DATETIME
  • Run a cronjob every second (or every 500 milliseconds... set this to whatever you want).
  • On every run, the job should check every row in the resources table. For every resource:
    1. determine how much time has passed since the last update (elapsedTime = currentTime - lastResourceDrop)
    1. determine how many resources the player got during that time: resourcesToAdd = floor(productionCooldown / elapsedTime)
    1. add the amount of time it took for them to get those resources: lastResourceDrop = lastResourceDrop + productionCooldown * resourcesToAdd

This is less complex, and therefore easier to troubleshoot, compared to the approach with multiple cronjobs. However, now we're iterating over every row of the database every single second, which is suboptimal. Here's how we can improve this further:

3) Lazy evaluation

Create a getPlayerResource method or API and use it whenever anything in your game wants to know the current amount of resources a player has. This method should:

  • Update the player's resources by following the steps above.
  • Return the player's current resource amount.

Pros:

  • No cronjobs
  • It only updates resources for active players. Inactive players won't slow down your algorithm.
  • Thread safe. If you perform all the database operations as a transaction, you won't run into corner cases where you update a player's resources twice in a row.

Cons:

  • Slightly slower than just reading a player's current resources without performing any checks or updates.
\$\endgroup\$
  • \$\begingroup\$ Great solution.Also i can call an update from the client when one of the buildings is ready to update the resources, that will suffice it. Thank you very much. \$\endgroup\$ – SegmentFault Nov 6 '17 at 21:57

Not the answer you're looking for? Browse other questions tagged or ask your own question.