Skip to content

fix: disable submission for global extensions with 0 workers#911

Merged
PythonFZ merged 2 commits intomainfrom
fix/907-disable-submit-zero-workers
Apr 8, 2026
Merged

fix: disable submission for global extensions with 0 workers#911
PythonFZ merged 2 commits intomainfrom
fix/907-disable-submit-zero-workers

Conversation

@PythonFZ
Copy link
Copy Markdown
Member

@PythonFZ PythonFZ commented Apr 4, 2026

Summary

Closes #907

  • Backend: submit_task() now rejects submissions for non-@internal jobs that have 0 connected workers (returns 409 with RFC 9457 problem detail)
  • Frontend: "Run Extension" button is disabled with a "No workers connected" tooltip when workerCount === 0 for non-internal jobs
  • Test: test_submit_global_task_no_workers_returns_409 verifies the backend guard

Test plan

  • All 305 joblib tests pass
  • TypeScript compiles cleanly
  • Manual: register a global extension, disconnect worker, verify submit button is disabled
  • Manual: verify tooltip shows "No workers connected"

🤖 Generated with Claude Code

Summary by CodeRabbit

Release Notes

  • New Features

    • Added validation to prevent task submission when no workers are connected to a job, returning a clear error message.
    • Enhanced button feedback with tooltips that indicate when no workers are available for the selected job.
  • Tests

    • Added test coverage for task submission when workers are unavailable.

PythonFZ and others added 2 commits April 4, 2026 12:56
Backend returns 409 when submitting to a non-@internal job with no
connected workers. Frontend disables the Run Extension button and shows
a "No workers connected" tooltip in the same scenario.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Apr 4, 2026

📝 Walkthrough

Walkthrough

This change implements worker availability validation for task submission. A new NoWorkersAvailable exception type was added and integrated into the backend router to reject submissions for non-internal jobs lacking connected workers. The frontend submit button now conditionally disables when workers are unavailable and displays corresponding tooltips.

Changes

Cohort / File(s) Summary
Frontend Submit Button Logic
frontend/src/components/SecondaryPanel.tsx
Replaced simple disabled check with noWorkers computation from selected job's WorkerJobLink count. Updated tooltip to show "No workers connected" for non-internal jobs without workers, or "Room is locked" when read-only. Expanded disabled conditions to include noWorkers state.
Exception Definition
src/zndraw_joblib/exceptions.py
Added NoWorkersAvailable exception class extending ProblemType with HTTP 409 status and "Conflict" title, integrating into RFC 9457 problem-type framework.
Backend Task Submission Validation
src/zndraw_joblib/router.py
Added pre-submission worker availability check in submit_task(): for non-@internal jobs, queries WorkerJobLink count and rejects with NoWorkersAvailable when count is zero. Check executes before task creation.
Test Coverage
tests/zndraw_joblib/test_router_task_submit.py
Added test test_submit_global_task_no_workers_returns_409 validating 202 response for initial submission, 204 for worker deletion, and 409 rejection on subsequent submission with "no connected workers" error detail.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant Frontend as Frontend<br/>(SecondaryPanel)
    participant Backend as Backend<br/>(router.py)
    participant DB as Database<br/>(WorkerJobLink)
    
    User->>Frontend: Click "Run Extension" button
    
    rect rgba(200, 100, 100, 0.5)
        Frontend->>Frontend: Check if job has workers<br/>(noWorkers computed)
        alt noWorkers = true
            Frontend->>User: Button disabled + tooltip<br/>"No workers connected"
        else noWorkers = false
            Frontend->>Backend: POST /rooms/{id}/tasks/{job}
            Backend->>DB: Query WorkerJobLink count<br/>for job
            DB-->>Backend: Count result
            
            alt count == 0 (non-@internal)
                Backend->>Backend: Raise NoWorkersAvailable
                Backend-->>Frontend: 409 Conflict response
                Frontend->>User: Display error
            else count > 0
                Backend->>DB: Create Task (PENDING)
                Backend-->>Frontend: 202 Accepted response
                Frontend->>User: Task submitted
            end
        end
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~22 minutes

Poem

Hop, skip, and a check so fine! 🐰
Workers counted, all in line,
No more tasks in pending plight,
The button knows when it's right!
Through router gates, the workers shine! ✨

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main change: disabling submission for global extensions when no workers are available.
Linked Issues check ✅ Passed All primary coding requirements from issue #907 are met: backend rejects submissions for non-@internal jobs with 0 workers (409 status), frontend disables button with tooltip, and unit test validates the rejection.
Out of Scope Changes check ✅ Passed All changes are directly aligned with issue #907 requirements: no extraneous modifications to unrelated functionality.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ 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 fix/907-disable-submit-zero-workers

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
Copy Markdown

@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.

🧹 Nitpick comments (1)
frontend/src/components/SecondaryPanel.tsx (1)

200-233: Consider extracting the IIFE to useMemo for readability.

The logic is correct, but the inline IIFE pattern is unusual in React components. Extracting noWorkers and tooltipTitle to useMemo would improve clarity and align with React conventions.

♻️ Optional refactor to useMemo
+ const noWorkers = useMemo(() => {
+   return (
+     selectedJob != null &&
+     !selectedJob.full_name.startsWith("@internal:") &&
+     selectedJob.workers.length === 0
+   );
+ }, [selectedJob]);
+
+ const submitTooltipTitle = useMemo(() => {
+   if (roomReadOnly) return "Room is locked";
+   if (noWorkers) return "No workers connected";
+   return "";
+ }, [roomReadOnly, noWorkers]);

Then in the JSX:

 {panelTitle !== "settings" && (
-  (() => {
-    const noWorkers = ...;
-    const tooltipTitle = ...;
-    return (
-      <Tooltip title={tooltipTitle}>
+  <Tooltip title={submitTooltipTitle}>
     <span>
       <Button
         ...
         disabled={
           isSubmitting ||
           isLoadingSchema ||
           roomReadOnly ||
           noWorkers
         }
         ...
       >
         {isSubmitting ? "Running..." : "Run Extension"}
       </Button>
     </span>
   </Tooltip>
-    );
-  })()
 )}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@frontend/src/components/SecondaryPanel.tsx` around lines 200 - 233, Extract
the inline IIFE logic into useMemo hooks: create a memoized noWorkers using
selectedJob and its properties (e.g. selectedJob.full_name,
selectedJob.workers.length) and a memoized tooltipTitle that depends on
roomReadOnly and noWorkers, then replace the IIFE JSX with a simple conditional
render that uses the memoized values; keep the Button props and handlers
(handleSubmit, isSubmitting, isLoadingSchema, roomReadOnly) unchanged and ensure
the disabled logic still references the memoized noWorkers and tooltipTitle is
passed into Tooltip.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@frontend/src/components/SecondaryPanel.tsx`:
- Around line 200-233: Extract the inline IIFE logic into useMemo hooks: create
a memoized noWorkers using selectedJob and its properties (e.g.
selectedJob.full_name, selectedJob.workers.length) and a memoized tooltipTitle
that depends on roomReadOnly and noWorkers, then replace the IIFE JSX with a
simple conditional render that uses the memoized values; keep the Button props
and handlers (handleSubmit, isSubmitting, isLoadingSchema, roomReadOnly)
unchanged and ensure the disabled logic still references the memoized noWorkers
and tooltipTitle is passed into Tooltip.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 67721d4e-d407-43de-8cfa-f065cc8228af

📥 Commits

Reviewing files that changed from the base of the PR and between 06cab0d and 806d2ee.

📒 Files selected for processing (4)
  • frontend/src/components/SecondaryPanel.tsx
  • src/zndraw_joblib/exceptions.py
  • src/zndraw_joblib/router.py
  • tests/zndraw_joblib/test_router_task_submit.py

@codecov-commenter
Copy link
Copy Markdown

codecov-commenter commented Apr 4, 2026

Codecov Report

❌ Patch coverage is 76.47059% with 4 lines in your changes missing coverage. Please review.
✅ Project coverage is 91.75%. Comparing base (06cab0d) to head (806d2ee).
✅ All tests successful. No failed tests found.

Files with missing lines Patch % Lines
src/zndraw_joblib/router.py 0.00% 4 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #911      +/-   ##
==========================================
- Coverage   91.78%   91.75%   -0.03%     
==========================================
  Files         246      246              
  Lines       22881    22898      +17     
==========================================
+ Hits        21001    21011      +10     
- Misses       1880     1887       +7     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@PythonFZ PythonFZ merged commit b6a871a into main Apr 8, 2026
6 checks passed
@PythonFZ PythonFZ deleted the fix/907-disable-submit-zero-workers branch April 8, 2026 07:37
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.

Disable submission for global extensions with 0 workers

2 participants