CRM_Queue_Queue - Add 'getStatistic($name)'. Deprecate 'numberOfItems()'
authorTim Otten <totten@civicrm.org>
Sat, 3 Sep 2022 01:55:52 +0000 (18:55 -0700)
committerTim Otten <totten@civicrm.org>
Sat, 3 Sep 2022 03:02:14 +0000 (20:02 -0700)
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
CRM/Queue/Queue/Memory.php
CRM/Queue/Queue/SqlTrait.php

index 9ff7d9b10c722ad9447a44617723f64fdbbc755b..7dfc1cdd6a21504fd08015beb14fd12906304776 100644 (file)
@@ -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.
index ad0bfd8ffdb66b801df5ff9a3648e0db8b1ffcec..e66791a5b8a73bf1fab4b03ee93ebbcb19ada50a 100644 (file)
@@ -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;
+    }
   }
 
   /**
index 8e191131e4d152f4e86e6c286f302c3954aae033..69f5cf2206897a4e0ddc49ef6997bf5b0fb52446 100644 (file)
@@ -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;
+    }
   }
 
   /**