Skip to content

feat(spider-huntsman): Replace custom error code with gRPC status. - #357

Closed
sitaowang1998 wants to merge 3 commits into
y-scope:mainfrom
sitaowang1998:error-to-status
Closed

feat(spider-huntsman): Replace custom error code with gRPC status.#357
sitaowang1998 wants to merge 3 commits into
y-scope:mainfrom
sitaowang1998:error-to-status

Conversation

@sitaowang1998

@sitaowang1998 sitaowang1998 commented Jun 25, 2026

Copy link
Copy Markdown
Collaborator

Description

This PR:

  • Remove error code in gRPC protobuf definition.
  • Add missing unpack for existing services.
  • Add error handlers and gRPC service in storage.
  • Add gRPC status code parsing in scheduler and execution manager.

Checklist

  • The PR satisfies the contribution guidelines.
  • This is a breaking change and that has been indicated in the PR title, OR this isn't a
    breaking change.
  • Necessary docs have been updated, OR no docs need to be updated.

Validation performed

  • GitHub workflows pass.

Summary by CodeRabbit

  • New Features

    • Added scheduler protocol support and scheduler registration handling.
    • Enabled additional storage gRPC operations, including ready-task polling, resource-group actions, execution-manager liveness, and scheduler lookup.
  • Bug Fixes

    • Improved error handling so failed requests return clearer, more consistent responses.
    • Tightened validation for IDs, IP addresses, ports, and task counts to reject invalid input earlier.
    • Updated response handling to better match the latest API shapes and prevent missing or empty payload issues.

@sitaowang1998
sitaowang1998 requested a review from a team as a code owner June 25, 2026 17:34
@coderabbitai

coderabbitai Bot commented Jun 25, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 325c97d5-4ee0-48cc-9cbe-939f4ddf6036

📥 Commits

Reviewing files that changed from the base of the PR and between 2c0f6ff and 05c6dbc.

⛔ Files ignored due to path filters (1)
  • components/spider-proto-rust/src/generated/storage.rs is excluded by !**/generated/**
📒 Files selected for processing (3)
  • components/spider-proto-rust/src/unpack/storage.rs
  • components/spider-proto/storage/storage.proto
  • components/spider-storage/src/grpc.rs
🚧 Files skipped from review as they are similar to previous changes (2)
  • components/spider-proto-rust/src/unpack/storage.rs
  • components/spider-proto/storage/storage.proto

Walkthrough

Storage and scheduler gRPC contracts now use direct payload fields, request unpackers and scheduler conversions were added, storage service RPCs and shared status helpers were implemented, and the execution-manager and scheduler clients were updated for the new response shapes and tonic status mappings.

Changes

Storage and scheduler gRPC alignment

Layer / File(s) Summary
Response contracts
components/spider-proto/storage/storage.proto
Storage RPC response messages now expose direct success payloads or empty messages, and VerifyResourceGroupRequest drops session_id.
Scheduler adapters and unpacking
components/spider-proto-rust/src/lib.rs, components/spider-proto-rust/src/scheduler.rs, components/spider-proto-rust/src/unpack/storage.rs
The scheduler module exports a RegisteredScheduler conversion, and request unpackers parse resource-group, execution-manager, scheduler, and ready-task inputs into typed values.
Central status helpers
components/spider-storage/src/grpc.rs
GrpcServiceState centralizes cache-internal and unexpected gRPC status handling, and new error handlers cover inbound queue, resource-group, execution-manager liveness, and scheduler registration services.
Service RPCs and test state
components/spider-storage/src/grpc.rs, components/spider-storage/src/state.rs
Inbound queue, resource-group, execution-manager, scheduler, and session RPCs now call inner methods, build ready-task responses, and return session ids; test_utils is crate-visible for the new tests.
Inbound queue polling mapping
components/spider-scheduler/src/error.rs, components/spider-scheduler/src/storage_client/grpc.rs
StorageClientError drops StaleSession, and the scheduler storage client maps inbound queue RPC failures through map_inbound_status while reading PollReadyTasksResponse.tasks directly.
Liveness response parsing
components/spider-execution-manager/src/client/grpc/liveness.rs
GrpcLivenessClient maps tonic statuses through map_liveness_status, reads direct registration and session_id response fields, and updates conversion tests.

Sequence Diagram(s)

Ready-task polling flow

sequenceDiagram
  participant InboundQueueService
  participant GrpcServiceState
  participant build_ready_tasks
  InboundQueueService->>GrpcServiceState: poll_ready_tasks / poll_ready_commit_tasks / poll_ready_cleanup_tasks
  GrpcServiceState->>build_ready_tasks: ReadyQueueEntry batches and task ids
  build_ready_tasks-->>GrpcServiceState: storage::ReadyTasks
  GrpcServiceState-->>InboundQueueService: PollReadyTasksResponse{tasks}
Loading

Execution-manager liveness response parsing

sequenceDiagram
  participant GrpcLivenessClient
  participant map_liveness_status
  participant register_response_to_result
  participant heartbeat_response_to_result
  GrpcLivenessClient->>map_liveness_status: tonic::Status
  map_liveness_status-->>GrpcLivenessClient: mapped LivenessResponseError
  GrpcLivenessClient->>register_response_to_result: RegisterExecutionManagerResponse
  register_response_to_result-->>GrpcLivenessClient: RegistrationResponse
  GrpcLivenessClient->>heartbeat_response_to_result: UpdateExecutionManagerHeartbeatResponse
  heartbeat_response_to_result-->>GrpcLivenessClient: session_id
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

  • y-scope/spider#327: Introduced the execution-manager liveness client traits that this PR’s liveness parsing now matches.
  • y-scope/spider#340: Added the execution-manager gRPC liveness surface that this PR updates to the new storage/proto response shapes.
  • y-scope/spider#347: Added scheduler registration gRPC/proto types that this PR’s scheduler module and storage client now consume.

Suggested reviewers

  • LinZhihao-723
🚥 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 captures the main change: replacing custom protobuf error handling with gRPC status codes.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
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.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

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

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@components/spider-execution-manager/src/client/grpc/liveness.rs`:
- Around line 112-114: Add a zero-value guard for execution_manager_id in the
registration handling path so it is validated before constructing the
RegistrationResponse. In the liveness client logic where RegistrationResponse is
built, mirror the existing session_id check by rejecting or handling a zero
execution_manager_id before calling
ExecutionManagerId::from(registration.execution_manager_id), ensuring invalid
sentinel values do not enter runtime state.

In `@components/spider-proto-rust/src/unpack/storage.rs`:
- Around line 209-220: Reject port 0 during scheduler registration in
RegisterSchedulerRequest::unpack, not just values outside u16. After parsing
self.port in the unpack implementation, add a validation that returns
invalid_argument when the port is 0, while still allowing only valid nonzero u16
ports to be returned from this method.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 97aa9cbb-034f-48fd-9a2d-bae74ebbba5a

📥 Commits

Reviewing files that changed from the base of the PR and between dfc8d5f and 2c0f6ff.

⛔ Files ignored due to path filters (1)
  • components/spider-proto-rust/src/generated/storage.rs is excluded by !**/generated/**
📒 Files selected for processing (10)
  • components/spider-execution-manager/src/client/grpc/liveness.rs
  • components/spider-proto-rust/src/lib.rs
  • components/spider-proto-rust/src/scheduler.rs
  • components/spider-proto-rust/src/unpack/storage.rs
  • components/spider-proto/storage/storage.proto
  • components/spider-scheduler/src/error.rs
  • components/spider-scheduler/src/storage_client/grpc.rs
  • components/spider-storage/src/grpc.rs
  • components/spider-storage/src/state.rs
  • components/spider-storage/src/state/test_utils.rs
💤 Files with no reviewable changes (1)
  • components/spider-scheduler/src/error.rs

Comment on lines 112 to 114
Ok(RegistrationResponse {
em_id: ExecutionManagerId::from(registration.execution_manager_id),
session_id: registration.session_id,

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.

🩺 Stability & Availability | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Description: Verify whether ExecutionManagerId permits zero and whether storage can emit zero.
# Expectation: If ExecutionManagerId is non-zero/reserved-zero, add a zero guard before Line 113.

set -euo pipefail

echo "ExecutionManagerId definition and constructors:"
rg -n -C4 'ExecutionManagerId|struct .*ExecutionManager|type .*ExecutionManager|impl .*ExecutionManager' components/spider-core components 2>/dev/null || true

echo
echo "ExecutionManagerRegistration construction sites:"
rg -n -C4 'ExecutionManagerRegistration|execution_manager_id:' components 2>/dev/null || true

Repository: y-scope/spider

Length of output: 50371


Add a zero-value guard for execution_manager_id

The session_id is guarded against zero, but execution_manager_id is converted directly without validation. The storage layer and system protocol require valid ExecutionManagerId values to be non-zero (as enforced by tests in components/spider-storage/src/grpc.rs), where zero serves as a sentinel for null or error states. A direct conversion without a check risks propagating an invalid identifier into the runtime state.

Context
            if registration.session_id == 0 {
                return Err(LivenessResponseError::Transport(
                    "register execution manager response carried a zero session id".to_owned(),
                ));
            }
+           if registration.execution_manager_id == 0 {
+               return Err(LivenessResponseError::Transport(
+                   "register execution manager response carried a zero execution manager id".to_owned(),
+               ));
+           }
            Ok(RegistrationResponse {
                em_id: ExecutionManagerId::from(registration.execution_manager_id),
                session_id: registration.session_id,
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
Ok(RegistrationResponse {
em_id: ExecutionManagerId::from(registration.execution_manager_id),
session_id: registration.session_id,
if registration.session_id == 0 {
return Err(LivenessResponseError::Transport(
"register execution manager response carried a zero session id".to_owned(),
));
}
if registration.execution_manager_id == 0 {
return Err(LivenessResponseError::Transport(
"register execution manager response carried a zero execution manager id".to_owned(),
));
}
Ok(RegistrationResponse {
em_id: ExecutionManagerId::from(registration.execution_manager_id),
session_id: registration.session_id,
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@components/spider-execution-manager/src/client/grpc/liveness.rs` around lines
112 - 114, Add a zero-value guard for execution_manager_id in the registration
handling path so it is validated before constructing the RegistrationResponse.
In the liveness client logic where RegistrationResponse is built, mirror the
existing session_id check by rejecting or handling a zero execution_manager_id
before calling ExecutionManagerId::from(registration.execution_manager_id),
ensuring invalid sentinel values do not enter runtime state.

Comment on lines +209 to +220
impl RequestUnpack for RegisterSchedulerRequest {
type Unpacked = (IpAddr, u16);

fn unpack(self) -> Result<Self::Unpacked, UnpackError> {
let ip_address = self
.ip_address
.parse::<IpAddr>()
.map_err(|error| invalid_argument(format!("invalid IP address: {error}")))?;
let port = u16::try_from(self.port)
.map_err(|_| invalid_argument(format!("port does not fit in `u16`: {}", self.port)))?;
Ok((ip_address, port))
}

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.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Reject port == 0 during scheduler registration.

Line 217 only checks that the value fits in u16. 0 still passes, gets persisted, and is later returned by get_schedulers, which leaves callers with an unusable endpoint.

Suggested fix
     fn unpack(self) -> Result<Self::Unpacked, UnpackError> {
         let ip_address = self
             .ip_address
             .parse::<IpAddr>()
             .map_err(|error| invalid_argument(format!("invalid IP address: {error}")))?;
         let port = u16::try_from(self.port)
             .map_err(|_| invalid_argument(format!("port does not fit in `u16`: {}", self.port)))?;
+        if port == 0 {
+            return Err(invalid_argument("port must be non-zero".to_owned()));
+        }
         Ok((ip_address, port))
     }
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
impl RequestUnpack for RegisterSchedulerRequest {
type Unpacked = (IpAddr, u16);
fn unpack(self) -> Result<Self::Unpacked, UnpackError> {
let ip_address = self
.ip_address
.parse::<IpAddr>()
.map_err(|error| invalid_argument(format!("invalid IP address: {error}")))?;
let port = u16::try_from(self.port)
.map_err(|_| invalid_argument(format!("port does not fit in `u16`: {}", self.port)))?;
Ok((ip_address, port))
}
impl RequestUnpack for RegisterSchedulerRequest {
type Unpacked = (IpAddr, u16);
fn unpack(self) -> Result<Self::Unpacked, UnpackError> {
let ip_address = self
.ip_address
.parse::<IpAddr>()
.map_err(|error| invalid_argument(format!("invalid IP address: {error}")))?;
let port = u16::try_from(self.port)
.map_err(|_| invalid_argument(format!("port does not fit in `u16`: {}", self.port)))?;
if port == 0 {
return Err(invalid_argument("port must be non-zero".to_owned()));
}
Ok((ip_address, port))
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@components/spider-proto-rust/src/unpack/storage.rs` around lines 209 - 220,
Reject port 0 during scheduler registration in RegisterSchedulerRequest::unpack,
not just values outside u16. After parsing self.port in the unpack
implementation, add a validation that returns invalid_argument when the port is
0, while still allowing only valid nonzero u16 ports to be returned from this
method.

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@components/spider-storage/src/grpc.rs`:
- Around line 561-569: The serialization path in `JobOutputsResponse` currently
wraps `SerializedTaskOutputs::serialize_with_size_hint()` errors as
`StorageServerError::Serde`, which then falls into the generic handler and
cancels the service. Update `job_orchestration_service_error_handler` so `Serde`
is handled explicitly as a non-fatal `INTERNAL` response, and ensure only truly
unrecoverable errors reach the branch that calls
`self.cancellation_token.cancel()`. Use the existing `StorageServerError` enum
and `job_orchestration_service_error_handler` logic to keep request-scoped
serialization failures from taking down the storage service.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 325c97d5-4ee0-48cc-9cbe-939f4ddf6036

📥 Commits

Reviewing files that changed from the base of the PR and between 2c0f6ff and 05c6dbc.

⛔ Files ignored due to path filters (1)
  • components/spider-proto-rust/src/generated/storage.rs is excluded by !**/generated/**
📒 Files selected for processing (3)
  • components/spider-proto-rust/src/unpack/storage.rs
  • components/spider-proto/storage/storage.proto
  • components/spider-storage/src/grpc.rs
🚧 Files skipped from review as they are similar to previous changes (2)
  • components/spider-proto-rust/src/unpack/storage.rs
  • components/spider-proto/storage/storage.proto

@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

Inline review comments failed to post. This is likely due to GitHub's internal server error or limits when posting large numbers of comments. If you are seeing this consistently it is likely a permissions issue. Please check "Moderation" -> "Code review limits" under your organization settings.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@components/spider-storage/src/grpc.rs`:
- Around line 561-569: The serialization path in `JobOutputsResponse` currently
wraps `SerializedTaskOutputs::serialize_with_size_hint()` errors as
`StorageServerError::Serde`, which then falls into the generic handler and
cancels the service. Update `job_orchestration_service_error_handler` so `Serde`
is handled explicitly as a non-fatal `INTERNAL` response, and ensure only truly
unrecoverable errors reach the branch that calls
`self.cancellation_token.cancel()`. Use the existing `StorageServerError` enum
and `job_orchestration_service_error_handler` logic to keep request-scoped
serialization failures from taking down the storage service.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 325c97d5-4ee0-48cc-9cbe-939f4ddf6036

📥 Commits

Reviewing files that changed from the base of the PR and between 2c0f6ff and 05c6dbc.

⛔ Files ignored due to path filters (1)
  • components/spider-proto-rust/src/generated/storage.rs is excluded by !**/generated/**
📒 Files selected for processing (3)
  • components/spider-proto-rust/src/unpack/storage.rs
  • components/spider-proto/storage/storage.proto
  • components/spider-storage/src/grpc.rs
🚧 Files skipped from review as they are similar to previous changes (2)
  • components/spider-proto-rust/src/unpack/storage.rs
  • components/spider-proto/storage/storage.proto
🛑 Comments failed to post (1)
components/spider-storage/src/grpc.rs (1)

561-569: 🩺 Stability & Availability | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Find the StorageServerError enum definition and any Serde handling arms.
rg -nP --type=rust -C2 '\bSerde\b' components/spider-storage/src
ast-grep run --pattern 'StorageServerError::Serde($_)' --lang rust components/spider-storage/src

Repository: y-scope/spider

Length of output: 1080


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Inspect the error type and the relevant handler arms in the gRPC service.
sed -n '1,120p' components/spider-storage/src/state/error.rs
printf '\n--- grpc handlers ---\n'
sed -n '430,490p' components/spider-storage/src/grpc.rs
printf '\n--- job outputs path ---\n'
sed -n '548,570p' components/spider-storage/src/grpc.rs

Repository: y-scope/spider

Length of output: 3934


Don’t cancel the storage service on Serde failures

SerializedTaskOutputs::serialize_with_size_hint() failures are wrapped as StorageServerError::Serde, but that variant has no dedicated handler and falls through to the generic catch-all that calls self.cancellation_token.cancel(). This turns a request-scoped serialization error into a service-wide outage. Map Serde to a non-fatal INTERNAL response instead of treating it as unrecoverable.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@components/spider-storage/src/grpc.rs` around lines 561 - 569, The
serialization path in `JobOutputsResponse` currently wraps
`SerializedTaskOutputs::serialize_with_size_hint()` errors as
`StorageServerError::Serde`, which then falls into the generic handler and
cancels the service. Update `job_orchestration_service_error_handler` so `Serde`
is handled explicitly as a non-fatal `INTERNAL` response, and ensure only truly
unrecoverable errors reach the branch that calls
`self.cancellation_token.cancel()`. Use the existing `StorageServerError` enum
and `job_orchestration_service_error_handler` logic to keep request-scoped
serialization failures from taking down the storage service.

@sitaowang1998

Copy link
Copy Markdown
Collaborator Author

Closed as will further split into two PRs.

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