Skip to content

feat: priority queue#292

Open
vertex451 wants to merge 4 commits into
mainfrom
artem/batching
Open

feat: priority queue#292
vertex451 wants to merge 4 commits into
mainfrom
artem/batching

Conversation

@vertex451

@vertex451 vertex451 commented Apr 22, 2026

Copy link
Copy Markdown
Contributor

📝 Description

This PR introduces a non-breaking change: I added the WithPriority broadcast option.
It does not affect existing library users but allows important messages to be pushed to the front of the queue.

How it works: each time the broadcaster is ready to send a transaction, it checks the priority queue first. If it’s empty, it pulls messages from the default queue.

🔧 Purpose of the Change

  • New feature implementation
  • Bug fix
  • Documentation update
  • Code refactoring
  • Dependency upgrade
  • Other: [specify]

📌 Related Issues

Related to akash-network/support#476, provider PR is on the way

✅ Checklist

  • I've updated relevant documentation
  • Code follows Akash Network's style guide
  • I've added/updated relevant unit tests
  • Dependencies have been properly updated
  • I agree and adhered to the Contribution Guidelines

📎 Notes for Reviewers

[Include any additional context, architectural decisions, or specific areas to focus on]

@vertex451 vertex451 requested a review from a team as a code owner April 22, 2026 15:56
@coderabbitai

coderabbitai Bot commented Apr 22, 2026

Copy link
Copy Markdown
Contributor

Walkthrough

Added a priority-enabled scheduling mechanism to serialBroadcaster: requests can be marked with WithPriority(), are enqueued into a priority deque, and the broadcaster preferentially dispatches priority items before pending ones; tests exercise FIFO semantics, preemption, error handling, and nil-option behavior.

Changes

Cohort / File(s) Summary
Priority Queue Implementation
go/node/client/v1beta3/tx.go
Added priority bool to BroadcastOptions and WithPriority() option. serialBroadcaster.run now maintains separate priority and pending deques, routes enqueued requests based on the option, and prefers draining priority when selecting the next dispatch. Added debug logging for enqueue/dispatch/completion and queue lengths.
Priority Queue Test Suite
go/node/client/v1beta3/tx_test.go
New tests and schedulerHarness exercising serialBroadcaster scheduling: FIFO for non-priority, priority preemption during in-flight dispatch, FIFO among priority items, mixed-queue draining order, handling of dispatch errors, and treatment of nil options as non-priority.

Sequence Diagram(s)

sequenceDiagram
    participant Enqueuer as Enqueuer
    participant Broadcaster as serialBroadcaster
    participant Dispatcher as Dispatcher

    Enqueuer->>Broadcaster: enqueue(req, opts)
    alt opts.priority == true
        Broadcaster->>Broadcaster: push to priority deque
    else opts.priority == false
        Broadcaster->>Broadcaster: push to pending deque
    end

    Note right of Broadcaster: When idle, tryBroadcast prefers priority deque
    Broadcaster->>Dispatcher: dispatch(next from priority or pending)
    Dispatcher-->>Broadcaster: dispatch result (error or nil)
    Broadcaster->>Enqueuer: notify completion
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐰 A hop, a bump, a queue split in two,
Priority leaps forward, pending waits true,
The broadcaster balances each little request,
Tests watch the order — they’ll sniff out the rest,
I celebrate with a twitch and a carrot-cheer crew! 🥕

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 33.33% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title 'feat: priority queue' is concise and directly reflects the main change—introducing priority queue functionality to the broadcaster. It clearly indicates the primary feature being added.
Description check ✅ Passed The description covers the key aspects of the change: what was added (WithPriority option), impact (non-breaking), and implementation details. Most template sections are completed, including purpose, related issues, and checklist items. However, the 'Notes for Reviewers' section is left blank.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

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

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch artem/batching

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 golangci-lint (2.11.4)

level=error msg="[linters_context] typechecking error: pattern ./...: directory prefix . does not contain main module or its selected dependencies"


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.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
go/node/client/v1beta3/tx.go (1)

469-494: ⚠️ Potential issue | 🟡 Minor

Strict priority can starve the pending queue.

tryBroadcast always prefers priority over pending with no aging/weighting. A sustained stream of WithPriority() callers will indefinitely delay non-priority work (including requests that may have been queued long before). If the intended callers are tightly controlled (e.g., a single provider hot-path), this is acceptable, but it is worth either:

  • documenting the starvation property on WithPriority so callers understand the contract, or
  • considering a simple fairness mechanism (e.g., drain at most N priority items before yielding one pending item, or age-based promotion).

No change required if starvation is an explicit design choice, but please make that choice explicit in the WithPriority godoc.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@go/node/client/v1beta3/tx.go` around lines 469 - 494, tryBroadcast currently
always selects priority over pending causing potential starvation; update it to
implement simple fairness (e.g., track a counter in tryBroadcast or surrounding
struct and drain at most N items from priority before allowing one pending item,
then reset the counter), or alternatively add/expand the WithPriority godoc to
explicitly document the starvation contract; refer to tryBroadcast, priority,
pending, WithPriority and ensure the chosen approach updates selection logic (or
godoc) consistently and includes any new counter/state variable if implementing
draining.
🧹 Nitpick comments (1)
go/node/client/v1beta3/tx.go (1)

208-216: Nit: document starvation/ordering contract.

Consider expanding the godoc to state explicitly that (a) priority requests FIFO among themselves, (b) a non-priority request already in-flight is not preempted (only pending non-priority work is), and (c) sustained priority traffic can indefinitely delay non-priority requests. This sets correct expectations for the forthcoming provider PR referenced in the description.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@go/node/client/v1beta3/tx.go` around lines 208 - 216, Update the godoc for
WithPriority (the BroadcastOption returned by WithPriority) to explicitly
document the ordering/starvation contract: state that priority requests are FIFO
among themselves, that an in-flight non-priority request is not preempted (only
pending non-priority work is delayed), and that sustained priority traffic can
indefinitely delay non-priority requests; reference the BroadcastOption/
BroadcastOptions and the opts.priority behavior in the comment so readers of
WithPriority and maintainers of the provider PR understand the guarantees.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In `@go/node/client/v1beta3/tx.go`:
- Around line 469-494: tryBroadcast currently always selects priority over
pending causing potential starvation; update it to implement simple fairness
(e.g., track a counter in tryBroadcast or surrounding struct and drain at most N
items from priority before allowing one pending item, then reset the counter),
or alternatively add/expand the WithPriority godoc to explicitly document the
starvation contract; refer to tryBroadcast, priority, pending, WithPriority and
ensure the chosen approach updates selection logic (or godoc) consistently and
includes any new counter/state variable if implementing draining.

---

Nitpick comments:
In `@go/node/client/v1beta3/tx.go`:
- Around line 208-216: Update the godoc for WithPriority (the BroadcastOption
returned by WithPriority) to explicitly document the ordering/starvation
contract: state that priority requests are FIFO among themselves, that an
in-flight non-priority request is not preempted (only pending non-priority work
is delayed), and that sustained priority traffic can indefinitely delay
non-priority requests; reference the BroadcastOption/ BroadcastOptions and the
opts.priority behavior in the comment so readers of WithPriority and maintainers
of the provider PR understand the guarantees.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 7b18d79a-0df2-48b2-b7f7-68428470d045

📥 Commits

Reviewing files that changed from the base of the PR and between 6e02ff0 and a1af032.

📒 Files selected for processing (2)
  • go/node/client/v1beta3/tx.go
  • go/node/client/v1beta3/tx_test.go

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick comments (2)
go/node/client/v1beta3/tx.go (2)

469-498: Strict priority scheduling can starve the pending queue.

tryBroadcast unconditionally prefers priority over pending. If a caller sustains a steady flow of WithPriority() requests (e.g., a provider's bid/lease loop), non-priority work can be delayed indefinitely. This is an inherent tradeoff of strict priority scheduling, but worth being intentional about since both deques are unbounded and there is no aging / weighted fairness. A few options to consider, in increasing order of complexity:

  • Document the starvation contract in WithPriority's godoc so callers understand priority is absolute, not weighted.
  • Cap the priority deque length (push back with an error / block) to bound the worst-case delay on pending.
  • Introduce periodic draining from pending (e.g., every N consecutive priority dispatches, serve one pending).

Not a blocker for merge — just flagging so it's a deliberate design choice.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@go/node/client/v1beta3/tx.go` around lines 469 - 498, tryBroadcast currently
always prefers the priority deque over pending, which can starve non-priority
work; either document that WithPriority is strict in its godoc or add simple
fairness: introduce a counter in the broadcaster (e.g.,
consecutivePriorityDispatches) and modify tryBroadcast to select pending when
the counter reaches a threshold N (reset the counter when you dispatch pending,
increment when you dispatch priority), or alternatively cap the priority deque
length and return/block on push for WithPriority; update tryBroadcast, the
surrounding scope to hold the counter and threshold constant, and/or add godoc
to WithPriority to make the chosen approach explicit.

460-467: Use Front() (with ok) instead of Peek(0) for clarity.

Minor readability nit — the edwingeng/deque/v2 API exposes Front() (T, bool) which more clearly communicates "look at the head without removing" than Peek(0) (which accepts an arbitrary index and panics on out-of-range). The code guards with q.Len() > 0 at lines 473 and 476, so functionally both are equivalent; this is purely a readability suggestion.

♻️ Optional refactor
-		req := q.Peek(0)
+		req, _ := q.Front()
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@go/node/client/v1beta3/tx.go` around lines 460 - 467, Replace usage of
Peek(0) with the deque Front() helper for clearer intent and safer bounds
handling: when inspecting the head of either deque (priority or pending) switch
calls like q.Peek(0) to q.Front() and handle the returned ok boolean (e.g., only
use the returned value when ok is true). Update any code paths that currently
rely on prior q.Len() checks to instead use the Front() ok result to guard
access in functions/methods around priority, pending, and the broadcast logic
that reference Peek(0) (e.g., where broadcastCh, broadcastDoneCh, tryBroadcast,
or send dispatch logic examines the deques).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@go/node/client/v1beta3/tx.go`:
- Around line 469-498: tryBroadcast currently always prefers the priority deque
over pending, which can starve non-priority work; either document that
WithPriority is strict in its godoc or add simple fairness: introduce a counter
in the broadcaster (e.g., consecutivePriorityDispatches) and modify tryBroadcast
to select pending when the counter reaches a threshold N (reset the counter when
you dispatch pending, increment when you dispatch priority), or alternatively
cap the priority deque length and return/block on push for WithPriority; update
tryBroadcast, the surrounding scope to hold the counter and threshold constant,
and/or add godoc to WithPriority to make the chosen approach explicit.
- Around line 460-467: Replace usage of Peek(0) with the deque Front() helper
for clearer intent and safer bounds handling: when inspecting the head of either
deque (priority or pending) switch calls like q.Peek(0) to q.Front() and handle
the returned ok boolean (e.g., only use the returned value when ok is true).
Update any code paths that currently rely on prior q.Len() checks to instead use
the Front() ok result to guard access in functions/methods around priority,
pending, and the broadcast logic that reference Peek(0) (e.g., where
broadcastCh, broadcastDoneCh, tryBroadcast, or send dispatch logic examines the
deques).

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: f4d0f19d-2140-4e93-9d4a-6964690dce8b

📥 Commits

Reviewing files that changed from the base of the PR and between a1af032 and 2173211.

📒 Files selected for processing (1)
  • go/node/client/v1beta3/tx.go

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant