From 7c516fcf799a8d26381210dcd95a34d9ce69a77b Mon Sep 17 00:00:00 2001 From: Tim Otten Date: Fri, 2 Sep 2022 18:55:52 -0700 Subject: [PATCH] CRM_Queue_Queue - Add 'getStatistic($name)'. Deprecate 'numberOfItems()' Should `numberOfItems()` tell you the _total_ number of items -- or the number of _ready_ items? Trick question. They can tell you different things: * When implementing a task-worker (which should start/stop based on available tasks), you'd use _ready_ items. * When implementing `existsQueue()` (which tells if you the queue has anything at all), you'd use _total_ items. This trick-question is why different implementations have computed `numberOfItems()` in different ways. This patch resolves the trick-question by deprecating `numberOfItems()` and replacing it with `getStatistic($name)`. --- CRM/Queue/Queue.php | 24 ++++++++++++++++++++++-- CRM/Queue/Queue/Memory.php | 33 ++++++++++++++++++++++++++++----- CRM/Queue/Queue/SqlTrait.php | 36 ++++++++++++++++++++++++------------ 3 files changed, 74 insertions(+), 19 deletions(-) diff --git a/CRM/Queue/Queue.php b/CRM/Queue/Queue.php index 9ff7d9b10c..7dfc1cdd6a 100644 --- a/CRM/Queue/Queue.php +++ b/CRM/Queue/Queue.php @@ -138,8 +138,28 @@ abstract class CRM_Queue_Queue { * Determine number of items remaining in the queue. * * @return int - */ - abstract public function numberOfItems(); + * @deprecated + * Use `getStatistic(string $name)` instead. + * The definition of `numberOfItems()` has become conflicted among different subclasses. + */ + public function numberOfItems() { + // This is the statistic traditionally reported by core queue implementations. + // However, it may not be as useful, and subclasses may have different interpretations. + return $this->getStatistic('total'); + } + + /** + * Get summary information about items in the queue. + * + * @param string $name + * The desired statistic. Ex: + * - 'ready': The number of items ready for execution (not currently claimed, not scheduled for future). + * - 'blocked': The number of items that may be runnable in the future, but cannot be run right now. + * - 'total': The total number of items known to the queue, regardless of whether their current status. + * @return int|float|null + * The value of the statistic, or NULL if the queue backend does not unsupport this statistic. + */ + abstract public function getStatistic(string $name); /** * Get the next item. diff --git a/CRM/Queue/Queue/Memory.php b/CRM/Queue/Queue/Memory.php index ad0bfd8ffd..e66791a5b8 100644 --- a/CRM/Queue/Queue/Memory.php +++ b/CRM/Queue/Queue/Memory.php @@ -110,12 +110,35 @@ class CRM_Queue_Queue_Memory extends CRM_Queue_Queue { } /** - * Determine number of items remaining in the queue. - * - * @return int + * @param string $name + * @return int|float|null + * @see \CRM_Queue_Queue::getStatistic() */ - public function numberOfItems(): int { - return count($this->items); + public function getStatistic(string $name) { + $ready = function(): int { + $now = CRM_Utils_Time::time(); + $ready = 0; + foreach ($this->items as $id => $item) { + if (empty($this->releaseTimes[$id]) || $this->releaseTimes[$id] <= $now) { + $ready++; + } + } + return $ready; + }; + + switch ($name) { + case 'ready': + return $ready(); + + case 'blocked': + return count($this->items) - $ready(); + + case 'total': + return count($this->items); + + default: + return NULL; + } } /** diff --git a/CRM/Queue/Queue/SqlTrait.php b/CRM/Queue/Queue/SqlTrait.php index 8e191131e4..69f5cf2206 100644 --- a/CRM/Queue/Queue/SqlTrait.php +++ b/CRM/Queue/Queue/SqlTrait.php @@ -47,22 +47,34 @@ trait CRM_Queue_Queue_SqlTrait { * @return bool */ public function existsQueue() { - return ($this->numberOfItems() > 0); + return ($this->getStatistic('total') > 0); } /** - * Determine number of items remaining in the queue. - * - * @return int + * @param string $name + * @return int|float|null + * @see \CRM_Queue_Queue::getStatistic() */ - public function numberOfItems() { - return (int) CRM_Core_DAO::singleValueQuery(' - SELECT count(*) - FROM civicrm_queue_item - WHERE queue_name = %1 - ', [ - 1 => [$this->getName(), 'String'], - ]); + public function getStatistic(string $name) { + switch ($name) { + case 'ready': + return (int) CRM_Core_DAO::singleValueQuery( + 'SELECT count(*) FROM civicrm_queue_item WHERE queue_name = %1 AND (release_time is null OR release_time <= FROM_UNIXTIME(%2))', + [1 => [$this->getName(), 'String'], 2 => [CRM_Utils_Time::time(), 'Int']]); + + case 'blocked': + return (int) CRM_Core_DAO::singleValueQuery( + 'SELECT count(*) FROM civicrm_queue_item WHERE queue_name = %1 AND release_time > FROM_UNIXTIME(%2)', + [1 => [$this->getName(), 'String'], 2 => [CRM_Utils_Time::time(), 'Int']]); + + case 'total': + return (int) CRM_Core_DAO::singleValueQuery( + 'SELECT count(*) FROM civicrm_queue_item WHERE queue_name = %1', + [1 => [$this->getName(), 'String']]); + + default: + return NULL; + } } /** -- 2.25.1