Dayo Posted March 31, 2020 Share Posted March 31, 2020 Im a big fan of cronless crons and have been pushing this idea for 10 years now! (see here) Ive had a few people ask if i can make this easier to work with in GLv2 so i have created a simple Cron class that will hopefully make life easier and give you a better understanding of cronless crons. Cron Class <?php class Cron { public function __construct($cronName, $cronType, $interval, $maxRepetitions = 1000) { global $db, $user; $this->db = $db; $this->user = $user; $this->settings = new Settings(); $this->cronName = $cronName; $this->cronType = $cronType; $this->maxRepetitions = $maxRepetitions; $this->interval = $interval; } public function updateLastRun() { if (!$this->getRepetitionCount()) return $this; $key = "cron-" . $this->cronName; $newTime = time() - (time() % $this->interval); if ($this->cronType == "user" && $this->user) { $time = $this->user->updateTimer($key, $newTime); } else if ($this->cronType == "system") { $time = $this->settings->update($key, $newTime); } return $this; } public function getRepetitionCount () { $key = "cron-" . $this->cronName; if ($this->cronType == "user" && $this->user) { $time = $this->user->getTimer($key, false); } else if ($this->cronType == "system") { $time = $this->settings->loadSetting($key); } $count = floor((time() - $time) / $this->interval); return $count > $this->maxRepetitions?$this->maxRepetitions:$count; } public function getCronDates() { $key = "cron-" . $this->cronName; if ($this->cronType == "user" && $this->user) { $time = $user->getTimer($key); } else if ($this->cronType == "system") { $time = $this->settings->loadSetting($key); } $count = floor((time() - intval($time)) / $this->interval); if ($count > $this->maxRepetitions) { $count = $this->maxRepetitions; } if (!$count) return array(); $start = time() - time() % $this->interval; $dates = array(); while ($count) { $dates[] = $start - ($this->interval * ($count - 1)); $count--; } return $dates; } } Usage Examples (moduleExample.hooks.php) <?php new Hook("userInformation", function ($user) { global $page; if ($user) { $oneMinCron = new Cron("addUserEnergy", "user", 60, $this->user->info->US_maxEnergy); $howManyTimesTheCronWouldHaveRun = $oneMinCron->getRepetitionCount(); $newEnergy = $howManyTimesTheCronWouldHaveRun * 2 + $this->user->info->US_maxEnergy; if ($newEnergy > $this->user->info->US_maxEnergy) { $newEnergy = $this->user->info->US_maxEnergy; } $this->user->set("US_maxEnergy", $newEnergy); $oneMinCron->updateLastRun(); } $systemCron = new Cron("everyHour", "system", 3600, 24); $datesAndTimeThatTheCronWouldHaveRan = $systemCron->getCronDates(); foreach ($datesAndTimeThatTheCronWouldHaveRan as $date) { /* do something here */ } $systemCron->updateLastRun(); }); Documentation __construct($cronName, $cronType, $interval, $maxRepetitions) $cronName - A unique name given to this cron, this is used to identify it in the database $cronType - This can be "user" or "system" user - This cron will only run when the user is active and playing the game, if they have been AFK for a period of time it will run the cron as many times as needed.(capped by the maxRepetitions) system - This cron is run when there is any activity on the game, it can be a logged in user or someone visiting the login page, if it has not been run for a while it will run as many times as needed (capped by the maxRepetitions) $interval - How often should the cron run (seconds) $maxRepetitions - The maximum times this cron will run getRepetitionCount() Returns how many times the cron would have ran if it was running away in the background getCronDates() Same as getRepetitionCount but instead of returning a numerical value it will return an array of dates and times when the cron would have ran. updateLastRun Updates the database storing when the cron was last run. If the cron was not run 6 Quote Link to comment Share on other sites More sharing options...
Dave Posted March 31, 2020 Share Posted March 31, 2020 I love the idea of cronless crons, as long as you don't randomly lag a user out for ~30 seconds performing some crazy intense logic as they're the first visitor in a few days. This is a nice simple implementation though! Thanks for sharing. I'd still promote deferring heavy, long running operations to an actual crontab. I remember this whole idea came around partially due to everyone using hosting which didn't support crons lower than 15 minutes, so neat to see it's coming back (shameless plug: even though MWG hosting supports minute crons). Quote Link to comment Share on other sites More sharing options...
SwiftGameR Posted March 31, 2020 Share Posted March 31, 2020 (edited) Yay so glad you got around to that will making my modules easier if requiring crons. Thanks Edited March 31, 2020 by Dayo Sorry for editing just wanted to remove the big code blocks Quote Link to comment Share on other sites More sharing options...
Dayo Posted March 31, 2020 Author Share Posted March 31, 2020 36 minutes ago, Dave said: I love the idea of cronless crons, as long as you don't randomly lag a user out for ~30 seconds performing some crazy intense logic as they're the first visitor in a few days. This is a nice simple implementation though! Thanks for sharing. Yeah that's why i like to separate user crons and system crons, as well as adding limits to how many times a cron can run. Plus features should be designed in a way so that if a game has no activity for 100 days does it really need to run 100 days worth of crons or can it run the past week. 36 minutes ago, Dave said: I remember this whole idea came around partially due to everyone using hosting which didn't support crons lower than 15 minutes, so neat to see it's coming back (shameless plug: even though MWG hosting supports minute crons). Yeah back in the days when people would find an illegal copy of McCodes and run it on a free host 😛 1 1 Quote Link to comment Share on other sites More sharing options...
KyleMassacre Posted March 31, 2020 Share Posted March 31, 2020 If you were targeting mainly only higher versions of PHP you could provide a callback to you methods you defined to run whatever you wish in that callback x number of times automatically. 1 Quote Link to comment Share on other sites More sharing options...
Dayo Posted April 1, 2020 Author Share Posted April 1, 2020 9 hours ago, KyleMassacre said: If you were targeting mainly only higher versions of PHP you could provide a callback to you methods you defined to run whatever you wish in that callback x number of times automatically. I am already adding the ability for that for when i build it directly into the core engine, it will support both the callback method and the methods above 2 Quote Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.