Skip to content

Conversation

@r2luna
Copy link
Owner

@r2luna r2luna commented Feb 12, 2026

  • feat: Add #[OnQueue] attribute for Tasks and Processes
  • docs: Add documentation for setting a specific queue

What:

  • Bug Fix
  • New Feature

Description:

Related:

Summary by CodeRabbit

  • New Features

    • Added OnQueue attribute to assign specific queues to Tasks and Processes.
    • Task-level queue assignments take precedence over Process-level queues.
    • Chained tasks inherit Process queue unless explicitly overridden.
  • Documentation

    • Added comprehensive guide explaining queue-specific behavior, precedence rules, execution flows, and practical usage examples.

Resolves #18 — declaring `public string $queue` on a Task causes a PHP
fatal error because Laravel's Queueable trait declares $queue without a
type hint. The new #[OnQueue('queue-name')] attribute sets the queue
via reflection, avoiding the property conflict.

When applied to a Process, the attribute sets the process's own queue
and propagates it to child tasks that don't define their own #[OnQueue].
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 12, 2026

📝 Walkthrough

Walkthrough

This pull request introduces the OnQueue attribute feature, enabling Tasks and Processes to specify their execution queue via PHP 8 annotation. The attribute is resolved through reflection during instantiation, and Processes propagate queue preferences to chained tasks. Queue metadata is tracked through the Brain map system.

Changes

Cohort / File(s) Summary
Attribute Definition
src/Attributes/OnQueue.php
New PHP 8 attribute class accepting a queue string parameter, targeting class-level annotations.
Core Implementation
src/Task.php, src/Process.php
Task and Process constructors now read OnQueue attributes via reflection and route to specified queues. Process additionally uses Queueable trait and propagates queue preferences to chained tasks via new resolveQueue helper.
Metadata Tracking
src/Console/BrainMap.php
Reflection-based map loading now extracts OnQueue attribute data and includes onQueue field in process and task metadata structures.
Test Fixtures & Tests
tests/Feature/Fixtures/OnQueueTask.php, tests/Feature/ProcessTest.php, tests/Feature/TaskTest.php, tests/Feature/Console/BrainMapTest.php
New test fixture with OnQueue annotation; comprehensive test coverage for queue dispatch behavior on Tasks, Processes, and chained tasks; updated test expectations to include onQueue metadata field.
Documentation
README.md
New section documenting OnQueue attribute usage with examples for Tasks and Processes, behavior precedence rules, and three illustrated queue execution flow diagrams.

Sequence Diagram

sequenceDiagram
    participant App as Application
    participant Task as Task/Process
    participant Reflect as Reflection System
    participant Attr as OnQueue Attribute
    participant Queue as Queue System

    App->>Task: Instantiate with OnQueue annotation
    Task->>Reflect: Read class attributes
    Reflect->>Attr: Locate OnQueue attribute
    Attr-->>Reflect: Return queue name
    Reflect-->>Task: Queue name resolved
    Task->>Queue: Route to specified queue
    Queue-->>App: Task dispatched to queue
Loading

Estimated Code Review Effort

🎯 4 (Complex) | ⏱️ ~50 minutes

Poem

🐰 A queue for each task, how neat and divine,
With OnQueue attributes, they'll run on their line,
Processes chain them with care and with grace,
Each job finds its home in the right queue-space,
Infrastructure blooms where the features align! 🌿

🚥 Pre-merge checks | ✅ 1 | ❌ 3
❌ Failed checks (3 warnings)
Check name Status Explanation Resolution
Title check ⚠️ Warning The title 'issue 18' is vague and generic, referring only to an issue number without describing the actual change being made. Use a descriptive title that summarizes the main change, such as 'Add OnQueue attribute for Tasks and Processes' or 'Implement queue assignment via #[OnQueue] attribute'.
Docstring Coverage ⚠️ Warning Docstring coverage is 63.64% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Merge Conflict Detection ⚠️ Warning ⚠️ Unable to check for merge conflicts: Failed to fetch base branch: fatal: refusing to fetch into branch 'refs/heads/main' checked out at '/home/jailuser/git'
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch issue-18
⚔️ Resolve merge conflicts (beta)
  • Auto-commit resolved conflicts to branch issue-18
  • Create stacked PR with resolved conflicts
  • Post resolved changes as copyable diffs in a comment

Warning

Review ran into problems

🔥 Problems

Git: Failed to clone repository. Please run the @coderabbitai full review command to re-trigger a full review. If the issue persists, set path_filters to include or exclude specific files.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Fix all issues with AI agents
In `@src/Process.php`:
- Around line 155-157: The current condition calls resolveQueue() three times
redundantly; change it to call resolveQueue() once (assign to $queue and then
check it) or even simpler use the existing property set by the constructor:
check $this->queue once and if not empty call $chain->onQueue($this->queue);
update the conditional around $chain->onQueue to use the single $queue variable
or $this->queue to avoid repeated reflection/attribute instantiation and
unnecessary reassignments.
- Around line 211-219: Hoist the call to resolveQueue() out of the per-task
loop: compute $processQueue once before the foreach that iterates over tasks
(instead of calling $this->resolveQueue() inside the loop), then inside the loop
use that cached $processQueue when checking $instance->queue and calling
$instance->onQueue($processQueue); alternatively you may use the already-set
$this->queue from the constructor instead of repeatedly calling resolveQueue();
keep the existing logic around ShouldQueue::class, $instance creation, and
dispatch($instance).
🧹 Nitpick comments (3)
src/Task.php (1)

62-67: Duplicate ReflectionClass instantiation per dispatch.

dispatch() (line 110) already creates a ReflectionClass(static::class), and here the constructor creates another one. Consider extracting the reflection instance to avoid the double cost — e.g., pass it through or cache it in a static/lazy property.

src/Process.php (2)

72-78: Constructor duplicates resolveQueue() logic.

The attribute-resolution logic here is identical to resolveQueue() (lines 270–279). Reuse the helper to keep a single source of truth, and also reuse the ReflectionClass already created on line 69:

♻️ Proposed fix
-        Context::add('process', [$this->name, $this->uuid]);
-
-        $onQueue = (new ReflectionClass(static::class))
-            ->getAttributes(OnQueue::class);
-
-        if ($onQueue !== []) {
-            $this->onQueue($onQueue[0]->newInstance()->queue);
-        }
+        Context::add('process', [$this->name, $this->uuid]);
+
+        $queue = $this->resolveQueue();
+        if ($queue !== null) {
+            $this->onQueue($queue);
+        }

267-280: Consider caching the resolved queue or relying on $this->queue.

resolveQueue() creates a new ReflectionClass on every call, yet the result is constant for the class. Since the constructor already stores the value via $this->onQueue(...), all downstream call sites (runInChain, run) could simply read $this->queue instead. This would make resolveQueue() needed only once — in the constructor — and the helper could be removed entirely.

Comment on lines +155 to +157
if (($queue = $this->resolveQueue()) !== null && ($queue = $this->resolveQueue()) !== '' && ($queue = $this->resolveQueue()) !== '0') {
$chain->onQueue($queue);
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

resolveQueue() is invoked three times (reflection + attribute instantiation each time).

Each ($queue = $this->resolveQueue()) reassigns $queue, so the first two calls are pure waste — only the last return value survives the && chain. Assign once, then guard:

🐛 Proposed fix
-        if (($queue = $this->resolveQueue()) !== null && ($queue = $this->resolveQueue()) !== '' && ($queue = $this->resolveQueue()) !== '0') {
+        $queue = $this->resolveQueue();
+
+        if ($queue !== null && $queue !== '' && $queue !== '0') {
             $chain->onQueue($queue);
         }

Additionally, since the constructor already calls $this->onQueue(...) (setting $this->queue), you could simplify the entire block to just read $this->queue instead of re-resolving via reflection:

if (!empty($this->queue)) {
    $chain->onQueue($this->queue);
}
🤖 Prompt for AI Agents
In `@src/Process.php` around lines 155 - 157, The current condition calls
resolveQueue() three times redundantly; change it to call resolveQueue() once
(assign to $queue and then check it) or even simpler use the existing property
set by the constructor: check $this->queue once and if not empty call
$chain->onQueue($this->queue); update the conditional around $chain->onQueue to
use the single $queue variable or $this->queue to avoid repeated
reflection/attribute instantiation and unnecessary reassignments.

Comment on lines 211 to +219
if ($reflectionClass->implementsInterface(ShouldQueue::class)) {
$task::dispatch($payload);
$processQueue = $this->resolveQueue();
$instance = new $task($payload);

if ($instance->queue === null && $processQueue !== null) {
$instance->onQueue($processQueue);
}

dispatch($instance);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion | 🟠 Major

resolveQueue() called per iteration inside the foreach loop — hoist it above the loop.

resolveQueue() performs reflection on every call, and the result is constant for the lifetime of the process. Move it before the loop, or simply use $this->queue which was already set in the constructor.

♻️ Proposed fix (minimal — hoist before the loop)

Add before line 185 (foreach):

$processQueue = $this->resolveQueue();

Then on line 212, remove the per-iteration call:

-                    $processQueue = $this->resolveQueue();
                     $instance = new $task($payload);
🤖 Prompt for AI Agents
In `@src/Process.php` around lines 211 - 219, Hoist the call to resolveQueue() out
of the per-task loop: compute $processQueue once before the foreach that
iterates over tasks (instead of calling $this->resolveQueue() inside the loop),
then inside the loop use that cached $processQueue when checking
$instance->queue and calling $instance->onQueue($processQueue); alternatively
you may use the already-set $this->queue from the constructor instead of
repeatedly calling resolveQueue(); keep the existing logic around
ShouldQueue::class, $instance creation, and dispatch($instance).

@r2luna r2luna merged commit e7423cc into main Feb 13, 2026
31 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant