i am running a webgame based on php . each player will create up to 100 attacks tasks that will be stored in db with details of it and end_time , every page load of any player on the website will call a function to check everything in db that supposed to end_time to be now or less . if found any , then it will start processing them ( make the actual attack and get its results ).
it is like travian if you know it . my issue happens when there are 20 task or more at the same moment then it will stuck and only process one task per page load ( which kills the game. )
i use foreach loop in order to process the array of queues that gotten by querying the db .
code is :
every page load will call :
 public function processQueue($type = 3, $playerId = 0)
    {
        global $gameConfig;
        $this->load_model('Mutex', 'mutex');
        $this->mutex->releaseOnTimeout();
        if ($this->mutex->lock()) { // locker to forbid 2 players from working on same rows and cause double values. 
            $this->processTaskQueue($type, $playerId);
            }
            $this->mutex->release();
        }
    }
Processing function :
public function processTaskQueue($type, $playerId)
    {
        $p_type = QS_ACCOUNT_DELETE . ',' . QS_MERCHANT_GO . ',' . QS_MERCHANT_BACK . ',' . QS_WAR_REINFORCE . ',' . QS_WAR_ATTACK . ',' . QS_WAR_ATTACK_PLUNDER . ',' . QS_WAR_ATTACK_SPY . ',' . QS_CREATEVILLAGE . ',' . QS_TATAR_RAISE . ',' . QS_SITE_RESET . ',' . QS_CROP_DELETE . ',' . QS_ARTEFACTS_RAISE;
        if ($type == 1) {
            $expr = "((q.player_id=" . $playerId . " AND q.proc_type!=" . QS_TROOP_TRAINING . ") OR q.proc_type IN (" . $p_type . "))";
        } elseif ($type == 2) {
            $expr = "(q.player_id=" . $playerId . " OR q.proc_type IN (" . $p_type . "))";
        } else {
            $expr = "q.proc_type!=" . QS_TROOP_TRAINING;
        }
        $result = db::get_all("SELECT  q.id, q.player_id, q.village_id, q.to_player_id, q.to_village_id, q.proc_type, q.building_id, q.proc_params, q.threads, q.execution_time, TIMESTAMPDIFF(SECOND, NOW(),q.end_date) remainingTimeInSeconds FROM p_queue q WHERE TIMESTAMPDIFF(SECOND, NOW(),(q.end_date - INTERVAL (q.execution_time*(q.threads-1)) SECOND)) <= 0 AND $expr ORDER BY TIMESTAMPDIFF(SECOND, NOW(),(q.end_date - INTERVAL (q.execution_time*(q.threads-1)) SECOND)) ASC");
        foreach ($result as $resultRow) {
            $remain = $resultRow['remainingTimeInSeconds'];
            if ($remain < 0) {
                $remain = 0;
            }
            $resultRow['threads_completed_num'] = $resultRow['execution_time'] <= 0 ? $resultRow['threads'] : floor(($resultRow['threads'] * $resultRow['execution_time'] - $remain) / $resultRow['execution_time']);
            if ($this->processTask($resultRow)) {
                unset($result);
                $this->processQueue($type, $playerId);
                break;
            }
        }
        unset($result);
    }
locker function :
define("__QS_LOCK_FS_", MODELS_DIR . "lock");
class Mutex_Model extends Model
{
    public function lock()
    {
        if (0 < db::count("UPDATE g_settings gs SET gs.qlocked=1, qlocked_date=NOW() WHERE gs.qlocked=0") && ($fp = fopen(__QS_LOCK_FS_, "r")) != FALSE) {
            if (flock($fp, LOCK_EX)) {
                fclose($fp);
                return TRUE;
            }
            fclose($fp);
        }
        return FALSE;
    }
    public function release()
    {
        $this->_releaseInternal();
        db::query("UPDATE g_settings gs SET gs.qlocked=0");
    }
    public function releaseOnTimeout()
    {
        if (0 < db::count("UPDATE g_settings gs SET gs.qlocked=0 WHERE gs.qlocked=1 AND TIME_TO_SEC(TIMEDIFF(NOW(), gs.qlocked_date)) > 120")) {
            $this->_releaseInternal();
        }
    }
    public function _releaseInternal()
    {
        if (($fp = fopen(__QS_LOCK_FS_, "r")) != FALSE) {
            flock($fp, LOCK_UN);
            fclose($fp);
        }
    }
}
what i need is to process all of the results in the array quickly ( could be 200 arrays in it or more ) and make it work all of the time without causing an issue ( tried ajax code to run every second but that cause missing stuff when a player logs out while it is running -- the row the script was handling while he is leaving will be miss ) and i need to process everything at once in it instead of the foreach loop ( it is very slow and will be stuck at every refresh )
i tried the following :
1- delete the break and make it continue running till it finished , but that gives players 500 http msg and make loading very very very slow for the one who got the locker opens ( mutex )
2- make cron job with php file that loops for 59s on processQueue function , but still it will only process like 10 - 20 tasks at one second maximum which is very slow
3- remove the locker which cause double values (meaning a. player send 50 solider they will return 100 )
my server infos are : 12 CPUs ( only 2 of them consumed ) 131,744,852 memory Configurations :
Start Servers [?] 5 default
10 Minimum Spare Servers [?] 5 default
10 Maximum Spare Servers [?] 10 default
20 Server Limit (Maximum: 20,000) [?] 256 default
8042 Max Request Workers [?] 150 default
8042 Max Connections Per Child [?] 10000 default
10000 Keep-Alive [?] On
PHP-FPM Pool options
Max Requests
95000
cPanel Default: 20
Max Children
10000
cPanel Default: 5
Process Idle Timeout  :30
i am really confused and hoping you can help me out here ..
 
    