Problem/Motivation

Many queueing systems (such as ActiveMQ, Beanstalkd etc) allow items to be given a priority when they are added to a queue, in order to allow applications to determine whether an item should be processed before others. The original issue to get queue API into D7 (http://drupal.org/node/391340) stated:

Queue cleanup and priorities are not yet there -- there is always a next, patch.

Therefore, the core queue API should allow createItem() to set a priority on an item.

Proposed resolution

Add a priority parameter to the createItem() method in the Drupal\Core\Queue\QueueInterface. Default this priority to zero to allow all existing queue usage to continue to work unmodified.

Remaining tasks

Get it RTBC and comitted :-)

User interface changes

None.

API changes

Update to Queue API (Drupal\Core\Queue\QueueInterface), and to the MemoryQueue and DatabaseQueue implementations in Core.

Original issue summary:

Many queueing systems (such as ActiveMQ, Beanstalkd etc) allow items to be given a priority when they are added to a queue, in order to allow applications to determine whether an item should be processed before others. The original issue to get queue API into D7 (http://drupal.org/node/391340) stated:

Queue cleanup and priorities are not yet there -- there is always a next, patch.

Therefore, this issue proposes a patch to the core queue API, allowing createItem() to set a priority. It exposes this in the Database Queue implementation, with priority used as an additional parameter to sort items by when claiming.

No change has so far been made to the MemoryQueue implementation, although this should also be considered.

First aim is to get a change in which is transparent and allows all existing tests to pass, a follow up will add tests to test that the queue prioritisation has the desired effect but I wanted to get views on the change before progressing.

Comments

tsphethean’s picture

StatusFileSize
new3.67 KB

First patch for testing.

tsphethean’s picture

Status: Active » Needs review

Status: Needs review » Needs work

The last submitted patch, queue_item_prioritisation-1913504-1.patch, failed testing.

tsphethean’s picture

Status: Needs work » Needs review
StatusFileSize
new4.23 KB

Add update hook to install priority column on upgraded sites. Will hopefully fix all the failing upgrade tests.

Status: Needs review » Needs work

The last submitted patch, queue_item_prioritisation-1913504-4.patch, failed testing.

tsphethean’s picture

Hmm. Test both in test bot and locally seem to be failing at the point where update.php is building it's batch, because its inserting into the queue table (with new priority field) before the update has run to add the new column.

How do you get around this? I could add something to update_fix_compatibility() or update_fix_d8_requirements() in update.inc - does that seem reasonable?

tsphethean’s picture

Initial add db_add_field to update_fix_d8_requirements() seems to fix failing upgrade tests locally. Will see what testbot thinks and then we can discuss if this is the right place to fix it...

tsphethean’s picture

Status: Needs work » Needs review
tsphethean’s picture

StatusFileSize
new7.88 KB

Updated patch with (locally) passing tests and a solution for the Memory queue class.

slashrsm’s picture

Status: Needs review » Needs work

Great job! Patch looks very good. I just have some (minor) comments.

+++ b/core/lib/Drupal/Core/Queue/DatabaseQueue.phpundefined
@@ -72,7 +73,7 @@ public function claimItem($lease_time = 30) {
+      $item = $this->connection->queryRange('SELECT data, item_id FROM {queue} q WHERE expire = 0 AND name = :name ORDER BY priority ASC, created ASC', 0, 1, array(':name' => $this->name))->fetchObject();

My personal preference are higher numbers that have priority before the lower ones. It seems more natural to me. This being just my personal preference please take it just as a well-intentioned and optional comment.

+++ b/core/lib/Drupal/Core/Queue/QueueInterface.phpundefined
@@ -21,13 +21,16 @@
+   * @param $priority
+   *   Priority to be associated with the new task in the queue.
+   *
    * @return
    *   TRUE if the item was successfully created and was (best effort) added
    *   to the queue, otherwise FALSE. We don't guarantee the item was
    *   committed to disk etc, but as far as we know, the item is now in the
    *   queue.
    */
-  public function createItem($data);
+  public function createItem($data, $priority = 0);

Related to the previous comment. No matter which approach we take (lower-highest or high-lowest), it should be clearly documented here. It will prevent a lot of confusion.

+++ b/core/modules/system/system.installundefined
@@ -993,6 +993,12 @@ function system_schema() {
+      'priority' => array(
+        'type' => 'int',
+        'not null' => TRUE,
+        'default' => 0,
+        'description' => 'The priority of the item.',

As chx already mentioned on IRC we need to modify existing index.

+++ b/core/modules/system/system.installundefined
@@ -2095,6 +2101,22 @@ function system_update_8048() {
+function system_update_8049() {
+  // Add the {queue}.priority column if it doesn't exist.
+  if (!db_field_exists('queue', 'priority')) {
+    $column = array(
+      'type' => 'int',
+      'not null' => TRUE,
+      'default' => 0,
+      'description' => 'The priority of the item.',
+    );
+    db_add_field('queue', 'priority', $column);
+  }
+}

You probably do not need this function here, as you already create this field in update_fix_d8_requirements().

tsphethean’s picture

Status: Needs work » Needs review
StatusFileSize
new8.22 KB

slashrsm - thanks for your review and comments (and thanks to chx if he's following). I've uploaded a revised patch with the following changes:

  • updated indexes on the queue table - this may need more looking at as all the combinations of indexed columns I tried in my local dev env were still showing "using where, using filesort" when running queries through explains.
  • added comment to explain how the priority is applied - I've stuck with lowest number = highest priority, higher number sinking to the bottom for now as this seems consistent with how Drupal treats weighting elsewhere (i.e. block priority, module priority etc). I'm not precious about it though so if there is a consensus it should be the other way round we can change it.
  • removed the system_update_n hook as advised

thanks again for the review.

slashrsm’s picture

Status: Needs review » Needs work

Looks good. I am just wondering if we could add just one index. If we'd put name on the first place in multi-column index there would be no need for single-column index on name. I was playing a bit with this idea and I think it could be achievable.

I was getting only "Using where" for query that loads new queue item for execution, which seems OK.

tsphethean’s picture

Status: Needs work » Needs review
StatusFileSize
new8.08 KB

Good idea - I wasn't sure if that would work, but EXPLAIN looks ok and talking through with a few people it sounds a good approach.

Revised patch changes the order of keys in the combined index and removes the single column index on name.

slashrsm’s picture

Status: Needs review » Reviewed & tested by the community

Looks good to me. Great job!

webchick’s picture

Issue tags: +RTBC Feb 18

I asked msonnabaum to take a look at this patch. In the meantime, tagging as something that was RTBC in time for feature freeze.

msonnabaum’s picture

Status: Reviewed & tested by the community » Needs work

This is not a feature we should include in the interface. Although it is supported by some queues, it's not supported by all (i.e. redis), which will make it very awkward to implement.

I've always solved this problem by putting high priority items in a dedicated queue, which works for most cases. If you need more than that, it can easily be solved in contrib.

tsphethean’s picture

Isn't that a decision to be made by the implementing Queue backend class about how to treat the priority, and if the queue doesn't support it then it ignores it. We already have queue features which arent supported by all backends (i.e. countItems() is not supported with any STOMP based queue backends, and Beanstalkd doesnt support createQueue or deleteQueue). By providing the option in the core classes which are able to support it we're providing more options for queue implementers?

catch’s picture

I've always solved this problem by putting high priority items in a dedicated queue, which works for most cases.

Yeah I've done the same.

We already have queue features which arent supported by all backends (i.e. countItems() is not supported with any STOMP based queue backends,

I think we could remove that, calling code can track how much it's processed if it needs to, it's only used one place in core outside of tests.

and Beanstalkd doesnt support createQueue or deleteQueue).

It doesn't really need to though. There's a difference between methods that might be needed by certain backends to function properly - i.e. if they have to create a schema, vs. methods that just can't be supported meaningfully.

tsphethean’s picture

Status: Needs work » Closed (won't fix)

Ok, fair enough. Will set this to won't fix then.

tsphethean’s picture

Issue summary: View changes

Updated issue summary for more detail and to meet convention.