public function enqueue()
{
$queue = new ArrayObject([]);
$config = $this->config();
try {
//Removing pending messages for terminated farms
$this->db->Execute("\n DELETE m FROM `messages` m, `servers` s, `farms` f\n WHERE s.`server_id` = m.`server_id` AND f.`id` = s.`farm_id`\n AND m.`type`= ? AND m.`status` = ? AND f.`status` = ?\n ", ["in", MESSAGE_STATUS::PENDING, FARM_STATUS::TERMINATED]);
//Removing pending messages for disappeared/terminated servers
$this->db->Execute("\n DELETE m FROM `messages` m\n WHERE m.`type`= ? AND m.`status` = ?\n AND NOT EXISTS (SELECT 1 FROM `servers` s WHERE s.`server_id` = m.`server_id`)\n ", ["in", MESSAGE_STATUS::PENDING]);
} catch (ADODB_Exception $e) {
if ($e->getCode() == ConnectionPool::ER_LOCK_DEADLOCK) {
$this->getLogger()->warn("DEADLOCK happened while removing messages of terminated farms");
} else {
throw $e;
}
}
$replicaMessages = $this->getReplicaTypes('type', '[\\w-]+');
$replicaAccounts = $this->getReplicaAccounts();
if (!empty($replicaMessages)) {
//m_priority column will be non empty if there is at least one message of this type for current unuque server
$stmt = ", MAX(FIND_IN_SET(m.`message_name`, '" . join(',', $replicaMessages) . "')) `m_priority` ";
} else {
$stmt = ", 0 `m_priority` ";
}
//Worker must handle messages for an each server sequentially and synchronously in the same order as they come
$rows = $this->db->Execute("\n SELECT m.`server_id`, s.`client_id` AS `account_id`\n " . $stmt . "\n FROM `messages` m\n INNER JOIN `servers` s ON s.`server_id` = m.`server_id`\n WHERE m.type = ?\n AND m.status = ?\n GROUP BY m.`server_id`\n ORDER BY `m_priority`\n ", ["in", MESSAGE_STATUS::PENDING]);
while ($row = $rows->FetchRow()) {
$t = new stdClass();
$t->serverId = $row['server_id'];
//Adjusts object with custom routing address.
//It determines which of the workers pool should handle the task.
//Handles priority of message names in the same order as it is provided in the config
$t->address = $this->name . '.' . ($row['m_priority'] > 0 ? $replicaMessages[$row['m_priority'] - 1] : 'all') . '.' . (!empty($replicaAccounts) ? in_array($row['account_id'], $replicaAccounts) ? $row['account_id'] : 'all' : 'all');
$queue->append($t);
}
if ($cnt = count($queue)) {
$this->getLogger()->info("%d server%s %s waiting for processing", $cnt, $cnt > 1 ? 's' : '', $cnt > 1 ? 'are' : 'is');
}
return $queue;
}