Last lesson introduced the queue as a ticket rail — a place to drop work for later. This lesson zooms in on the "dropping work" half specifically: the realistic patterns you'll actually use for adding items programmatically, beyond a single hardcoded string.
What you'll learn in this lesson
- Adding items from a loop (bulk enqueuing)
- Adding items conditionally, based on business logic
- Checking queue size before and after, and why that matters operationally
- The real form-submit pattern from the Examples module's queue_example
The real submit handler
Here's the actual "add to queue" submit handler from queue_example's form:
public function submitAddQueueItem(array &$form, FormStateInterface $form_state) {
$queue = $this->queueFactory->get($form_state->getValue('queue_name'));
// There is no harm in trying to recreate existing.
$queue->createQueue();
// Queue the string.
$queue->createItem($form_state->getValue('string_to_add'));
$count = $queue->numberOfItems();
$this->messenger()->addMessage(
$this->t(
'Queued your string (@string_to_add). There are now @count items in the queue.',
['@count' => $count, '@string_to_add' => $form_state->getValue('string_to_add')]
)
);
$form_state->setRebuild();
}
Notice it immediately calls numberOfItems() right after adding — that's not decoration, it's a genuinely useful pattern: reporting the queue's new size back to whoever triggered the add gives them confidence the item actually landed, without needing to inspect the database directly.
Bulk enqueuing from a loop
$queue = $this->queueFactory->get('my_module_notifications');
$queue->createQueue();
foreach ($user_ids as $uid) {
$queue->createItem([
'uid' => $uid,
'message' => $message,
]);
}
This is the realistic version of what a bulk operation looks like: get the queue and create it once, outside the loop, then call createItem() once per unit of work inside it. Each item is a small associative array — enough data for a worker to redo the notification later, nothing more.
Adding conditionally
if ($node->isPublished() && !$node->get('field_already_notified')->value) {
$queue->createItem(['nid' => $node->id()]);
}
There's nothing special about conditional enqueuing — it's just an ordinary if around a createItem() call. The important habit is deciding eligibility at enqueue time using data you already have, rather than queuing everything and making the worker re-check the same condition later, which just wastes a queue slot on work that was never going to happen.
numberOfItems() is cheap to call and worth exposing on an admin status page or logging periodically — a queue that keeps climbing, never draining, is an early warning sign worth catching before it becomes a real backlog.Quick check: you're enqueuing 50,000 items in a single batch operation. Should you call
$queue->createQueue()once before the loop, or once per item inside it? If you said once before — you've got it. It's idempotent and cheap, but there's still no reason to call it 50,000 times when once guarantees the same result.
Key takeaways
- Call
createQueue()once before a loop ofcreateItem()calls, not inside the loop. - Queue small, self-contained arrays or scalars — enough data to redo the work, not live objects.
- Decide eligibility (which items are actually worth queuing) at enqueue time, not inside the worker.
numberOfItems()is a cheap, useful health signal — watch it for unbounded growth in production.
Coming up next
Items are piling up on the queue — now you need something to actually take them off and do the work. Next: writing a real QueueWorker plugin, the piece that processes each item.