Skip to content
This repository was archived by the owner on Mar 5, 2026. It is now read-only.

feat(queue): add queue monitoring dashboard#9

Open
rohitg00 wants to merge 4 commits intomainfrom
rohit/queue-dashboard
Open

feat(queue): add queue monitoring dashboard#9
rohitg00 wants to merge 4 commits intomainfrom
rohit/queue-dashboard

Conversation

@rohitg00
Copy link
Copy Markdown
Contributor

@rohitg00 rohitg00 commented Feb 12, 2026

Summary

  • Add queue monitoring dashboard with full visibility into queue states (waiting, active, delayed, DLQ)
  • Visual separation of healthy queues and dead letter queues in sidebar
  • Redrive capability for DLQ entries with two-step confirmation
  • 6 new bridge HTTP endpoints: queue list, stats, jobs, job detail, redrive, DLQ count
  • New /queues route with 3-panel layout, search, pagination, and job detail viewer
  • Queue health card on dashboard homepage
  • Mobile responsive with slide-out sidebar drawer

Changes

Bridge (Rust)

  • functions.rs: 6 new handlers (handle_queues_list, handle_queue_stats, handle_queue_jobs, handle_queue_job, handle_queue_redrive, handle_queue_dlq_count) + fix path_parameters key in handle_state_item_delete
  • triggers.rs: 6 new HTTP trigger registrations under /_console/queues/*
  • Limit parameter clamped to max 500 to prevent abuse

Frontend

  • routes/queues.tsx: Full queue dashboard page with DLQ/queue visual separation
  • api/queues/queues.ts: API layer with types (QueueInfo, QueueJob, DlqEntry)
  • api/queries.ts: React Query hooks for queues
  • components/layout/Sidebar.tsx: Added Queues nav entry
  • routes/index.tsx: Queue health summary card on dashboard

Bug fixes

  • Fixed handle_state_item_delete using wrong key (path_params -> path_parameters)
  • Removed debug println! from handle_state_item_delete
  • Fixed unused queryClient import in states.tsx

Test plan

  • Start engine with queue module enabled
  • Enqueue test jobs via SDK
  • Navigate to /queues and verify queue list, job counts
  • Click queue to see jobs table with pagination
  • Click DLQ section to see failed jobs with error details
  • Test redrive: click Redrive All -> confirm -> verify jobs move back to waiting
  • Verify job detail panel shows metadata and payload
  • Test search filtering in sidebar
  • Verify mobile responsive layout
  • cargo check passes for console-rust
  • tsc -b && vite build passes for console-frontend

Depends on

  • iii-hq/iii rohit/queue-dashboard-introspection branch (engine-side queue introspection functions)

Summary by CodeRabbit

  • New Features
    • Added a Queues section (sidebar entry and route) to manage and monitor job queues.
    • View jobs by queue and state (waiting, active, delayed, dead-letter) with pagination.
    • See detailed job info (payload, metadata, error details) in a side panel.
    • Redrive dead-letter queue items and refresh queue stats.
    • Search and filter queues with periodic background refresh.

Add queue introspection UI with job browsing, DLQ management, and redrive support.

- Bridge: 6 queue handlers (list, stats, jobs, job, redrive, dlq-count) using engine.console.* naming
- Frontend: Full queue dashboard with 3-panel layout, job detail view, DLQ redrive
- API: Queue fetch functions with React Query integration (5s auto-refresh)
- Nav: Added Queues entry to sidebar between Streams and Functions
@rohitg00 rohitg00 force-pushed the rohit/queue-dashboard branch from 0b774d2 to 73c820f Compare February 12, 2026 14:37
@andersonleal
Copy link
Copy Markdown
Contributor

Code Review Report: PR #9feat(queue): add queue monitoring dashboard

Reviewed by: Security, Architecture, Performance, Code Quality (4 parallel AI reviewers)
Files reviewed: 8 (+971 lines)


Critical (0)

No critical findings.


High (6)

H1. Weak Type Safety — unknown[] cascades type assertions everywhere

  • File: api/queues/queues.ts:58-67, routes/queues.tsx (throughout)
  • Dimensions: Quality, Architecture
  • fetchQueueJobs returns jobs: unknown[], forcing ~10 as Record<string, unknown> casts. No compile-time safety for job field access — API shape changes would silently break the UI.
  • Fix: Return QueueJob[] | DlqEntry[] or use a discriminated union response type. Update JobDetailPanel props accordingly.

H2. Missing input validation for queue names and job IDs (Rust)

  • File: bridge/functions.rs:590-735
  • Dimension: Security
  • Queue names and job IDs extracted from user input are only checked for emptiness. No length limits, character validation, or format checks before passing to the engine SDK.
  • Fix: Add a validate_queue_name() helper (alphanumeric + -_.:, max 128 chars) and a validate_job_id() helper. Apply before all call_with_timeout calls.

H3. Monolithic 634-line route component

  • File: routes/queues.tsx:1-634
  • Dimension: Architecture
  • All UI concerns (sidebar, table, tabs, mobile drawer, pagination, redrive confirmation, job detail) live in one component with 11 useState calls. Compare: traces.tsx extracts 7+ dedicated components under components/traces/.
  • Fix: Extract QueueSidebar, QueueJobsTable, RedriveConfirmation, MobileQueueDrawer into components/queues/.

H4. Aggressive polling without visibility check

  • File: api/queries.ts:232-238
  • Dimension: Performance
  • queuesQuery polls every 5s via refetchInterval: 5000 unconditionally — even when the browser tab is hidden or the user is on a different route.
  • Fix: Add refetchIntervalInBackground: false.

H5. Excessive re-renders from 11 independent useState calls

  • File: routes/queues.tsx:42-52
  • Dimension: Performance
  • handleSelectQueue updates 5+ state variables, each triggering a separate render pass through the entire 634-line component tree.
  • Fix: Consolidate related state into useReducer and memoize expensive sub-components.

H6. Silent error swallowing in fetchQueueJob

  • File: api/queues/queues.ts:70-78
  • Dimension: Quality
  • if (!res.ok) return null discards HTTP status, error messages, and stack traces. The UI cannot distinguish "job not found" from "server error" or "network failure".
  • Fix: Throw with error detail from response body (matching the throw new Error(...) pattern used in other functions).

Medium (7)

M1. No rate limiting or audit logging for destructive redrive operation

  • File: bridge/functions.rs:689-711 | Dimension: Security
  • handle_queue_redrive moves all DLQ jobs back with no throttling or audit trail.
  • Fix: Add tracing::warn! before and tracing::info!/tracing::error! after.

M2. Inconsistent HTTP methods — POST for read operations

  • File: api/queues/queues.ts:32-85, bridge/triggers.rs:77-89 | Dimension: Architecture
  • fetchQueueStats, fetchQueueJobs, fetchQueueJob use POST for idempotent reads. Existing patterns (fetchStateGroups) use GET.
  • Fix: Use GET with query parameters for read endpoints, or document the rationale.

M3. JSON.stringify per row on every render

  • File: routes/queues.tsx:421-423 | Dimensions: Performance, Quality
  • Serialization runs on every row (up to 50) on every render. Can also throw on circular references.
  • Fix: Pre-compute previews in a useMemo over the jobs array; wrap in try/catch.

M4. Broad query invalidation on redrive

  • File: routes/queues.tsx:75-80 | Dimension: Performance
  • invalidateQueries({ queryKey: ['queue-jobs'] }) invalidates ALL cached job queries, not just the affected queue.
  • Fix: Scope to ['queue-jobs', selectedQueue] with exact: false.

M5. Missing staleTime on job queries

  • File: api/queries.ts:240-246 | Dimension: Performance
  • No staleTime means data is stale immediately, causing redundant refetches on re-renders.
  • Fix: Add staleTime: 3000.

M6. Suppressed exhaustive deps lint rule

  • File: routes/queues.tsx:102-107 | Dimension: Quality
  • useEffect with biome-ignore suppression — missing selectedQueue in deps.
  • Fix: Include selectedQueue in the dependency array.

M7. DRY violation — topic extraction repeated 3 times in Rust

  • File: bridge/functions.rs:591-595, 690-694, 714-718 | Dimensions: Quality, Architecture
  • The body→queue extraction pattern is copy-pasted in 3 handlers.
  • Fix: Extract fn extract_queue_name(input: &Value) -> Option<&str>.

Low (7)

# Finding File Dimension
L1 No state parameter validation in Rust (state can be any string) functions.rs:621-624 Quality
L2 Fragile implicit mapping between JobState and QueueInfo fields via indexing queues.tsx:127-130 Quality
L3 No search debouncing — filter recalculates on every keystroke queues.tsx:176-182 Performance
L4 CSRF protection relies solely on CORS (acceptable for local dev tool) server.rs:160-167 Security
L5 Frontend JobState type only enforced at compile-time, no runtime check queues.ts:57-64 Security
L6 Timeout values could be more granular (2s for list, 3s for pagination) functions.rs (all handlers) Performance
L7 fetchQueueJob and fetchQueueStats exported but unused in queries api/index.ts:89 Architecture

Summary

Severity Count
Critical 0
High 6
Medium 7
Low 7
Total 20

Suggested remediation order:

  1. H1 + H6 — Fix type safety and error handling (quick wins, high impact)
  2. H2 — Add input validation in Rust handlers (security)
  3. H4 + M5 — Add refetchIntervalInBackground: false and staleTime (one-liners)
  4. M4 — Scope query invalidation (one-liner)
  5. H3 + H5 — Component decomposition (larger refactor, can be follow-up PR)

Overall: The feature is well-structured and follows existing codebase conventions in most areas. Main concerns are type safety erosion from unknown[], missing backend input validation, and the monolithic component. The polling and re-render issues are straightforward to fix. Recommend addressing H1-H2 and the medium items before merge; component decomposition (H3) could be a follow-up.

H1: Replace unknown[] with QueueJob | DlqEntry typed unions
H2: Add validate_queue_name/validate_job_id in bridge handlers
H4: Add refetchIntervalInBackground: false to queuesQuery
H6: Throw on fetchQueueJob error instead of returning null
M1: Add audit logging for redrive operations
M4: Scope query invalidation to selected queue on redrive
M5: Add staleTime: 3000 to queue jobs query
M6: Fix exhaustive deps - add selectedQueue to useEffect
M7: Extract extract_queue_name helper to DRY topic extraction
Return null for 404 responses (job not found) instead of throwing,
matching the QueueJob | null return type signature.
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Feb 13, 2026

📝 Walkthrough

Walkthrough

Adds a full queue management feature: typed frontend API and React Query helpers, a Queues UI route with list/detail/DLQ/redrive flows, sidebar navigation and route registration, and new Rust bridge handlers and HTTP trigger mappings for queue operations.

Changes

Cohort / File(s) Summary
Frontend API & Queries
packages/console-frontend/src/api/index.ts, packages/console-frontend/src/api/queries.ts, packages/console-frontend/src/api/queues/queues.ts
Adds a typed queues API module (types: JobState, QueueInfo, QueueJob, DlqEntry) and functions (fetchQueues, fetchQueueStats, fetchQueueJobs, fetchQueueJob, redriveQueue); exposes them in index.ts and adds React Query helpers (queuesQuery, queueJobsQuery).
Frontend UI, Routing & Nav
packages/console-frontend/src/components/layout/Sidebar.tsx, packages/console-frontend/src/routeTree.gen.ts, packages/console-frontend/src/routes/queues.tsx
Adds "Queues" sidebar item, integrates /queues into the route tree, and implements QueuesPage route component with queue list, job list (states/tabs), DLQ handling, job detail panel, pagination, and redrive mutation.
Rust Bridge & Triggers
packages/console-rust/src/bridge/functions.rs, packages/console-rust/src/bridge/triggers.rs
Adds input validation helpers, queue RPC handlers (list, stats, jobs, job, redrive, dlq_count) with paging and error handling, and registers corresponding HTTP trigger mappings.

Sequence Diagram

sequenceDiagram
    participant User
    participant UI as QueuesPage
    participant Query as ReactQuery
    participant API as Queues API
    participant Backend as Rust Bridge

    User->>UI: Open /queues
    UI->>Query: prefetch queuesQuery
    Query->>API: fetchQueues()
    API->>Backend: engine.console.queues_list
    Backend-->>API: { queues: QueueInfo[] }
    API-->>Query: queues data
    Query-->>UI: render queues

    User->>UI: Select queue / change tab / page
    UI->>Query: queueJobsQuery(queue, state, offset, limit)
    Query->>API: fetchQueueJobs(...)
    API->>Backend: engine.console.queue_jobs
    Backend-->>API: { jobs, count, offset, limit }
    API-->>Query: jobs data
    Query-->>UI: display jobs

    User->>UI: Open job detail
    UI->>API: fetchQueueJob(queue, jobId)
    API->>Backend: engine.console.queue_job
    Backend-->>API: QueueJob | null
    API-->>UI: job detail

    User->>UI: Trigger redrive
    UI->>API: redriveQueue(queue)
    API->>Backend: engine.console.queue_redrive
    Backend-->>API: success
    API-->>Query: invalidate queues/jobs queries
    Query-->>UI: refreshed data / confirmation
Loading

Estimated Code Review Effort

🎯 4 (Complex) | ⏱️ ~50 minutes

Possibly related PRs

Suggested reviewers

  • sergiofilhowz

Poem

"I hopped through queues both near and far,
I counted jobs beneath each star,
DLQs sighed and then took flight,
Redrives hummed into the night,
Now queues align — a rabbit's work, hurrah!" 🐇✨

🚥 Pre-merge checks | ✅ 3 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 8.70% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat(queue): add queue monitoring dashboard' accurately summarizes the primary change—introducing a complete queue monitoring feature with backend endpoints, frontend dashboard, and navigation updates.
Merge Conflict Detection ✅ Passed ✅ No merge conflicts detected when merging into main

✏️ 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 rohit/queue-dashboard

No actionable comments were generated in the recent review. 🎉

🧹 Recent nitpick comments
packages/console-rust/src/bridge/functions.rs (1)

58-64: Consider extending this helper to include validation (DRY improvement).

extract_queue_name is used by 3 handlers but handle_queue_jobs and handle_queue_job manually extract the queue name with a slightly different pattern. This creates inconsistency and relates to the PR comment M7.

Consider a combined helper that extracts and validates:

♻️ Proposed refactor to consolidate extraction and validation
-fn extract_queue_name(input: &Value) -> Option<&str> {
-    input
-        .get("body")
-        .and_then(|b| b.get("queue"))
-        .and_then(|v| v.as_str())
-        .or_else(|| input.get("queue").and_then(|v| v.as_str()))
-}
+fn extract_queue_name(input: &Value) -> Option<&str> {
+    input
+        .get("body")
+        .and_then(|b| b.get("queue"))
+        .and_then(|v| v.as_str())
+        .or_else(|| input.get("queue").and_then(|v| v.as_str()))
+}
+
+fn extract_and_validate_queue_name(input: &Value) -> Result<String, Value> {
+    match extract_queue_name(input) {
+        Some(name) => validate_queue_name(name),
+        None => Err(error_response(iii_sdk::IIIError::Handler(
+            "Missing queue name in request".to_string(),
+        ))),
+    }
+}

Then handlers can use let topic = extract_and_validate_queue_name(&input)?; pattern with early return.


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

Engine registers queue functions under #[service(name = "queue")],
so full paths are queue.list_queues, queue.stats, etc. Without the
prefix, call_with_timeout would fail to resolve the functions at
runtime.
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants