Skip to content

Conversation

@zhansan114514
Copy link
Contributor

@zhansan114514 zhansan114514 commented Oct 4, 2025

Summary by CodeRabbit

  • New Features

    • Added job suspension and resumption: pause running jobs to free resources and resume later.
    • New CLI commands: suspend and resume .
    • Task status now includes “Suspended” (aliases: suspended, suspend, s).
    • JSON output supports suspend/resume responses.
  • Documentation

    • Help output updated with usage and descriptions for suspend and resume commands.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Oct 4, 2025

Walkthrough

Adds suspend/resume job control: new CLI commands, parser types, handlers, and help entries; ccontrol implements SuspendJobs/ResumeJobs that call ModifyTask RPC with new Suspend/Resume attributes. Protos add Suspend/Resume attributes and a Suspended task status. Utility parsing recognizes "suspend"/"suspended"/"s". Output follows existing JSON/summary patterns.

Changes

Cohort / File(s) Summary
CControl operations
internal/ccontrol/ccontrol.go
Adds public functions SuspendJobs(jobs string) and ResumeJobs(jobs string): parse comma-separated job IDs, build ModifyTaskRequest with Attribute = Suspend/Resume and current UID, call stub.ModifyTask, handle RPC errors, and emit JSON or summarized output.
Command dispatch & UX
internal/ccontrol/cmd.go, internal/ccontrol/help.go, internal/ccontrol/parser.go
Adds suspend and resume CLI commands: new parser types SuspendCommand/ResumeCommand, dispatcher handlers executeSuspendCommand/executeResumeCommand, validation of IDs, and help text entries; extends action/ID/KV accessor logic to include the new commands.
Utility status parsing
internal/util/string.go
Extends ParseTaskStatusName to accept suspended, suspend, and s mapping to protos.TaskStatus_Suspended.
Protocol buffers
protos/Crane.proto, protos/PublicDefs.proto
Crane.proto: adds ModifyTaskRequest.TargetAttributes values Suspend = 3, Resume = 4. PublicDefs.proto: adds TaskStatus Suspended = 10.

Sequence Diagram(s)

sequenceDiagram
  participant User
  participant CLI as CControl CLI
  participant Parser
  participant Ctl as CControl
  participant RPC as gRPC Stub
  participant Srv as Server

  User->>CLI: ccontrol suspend <jobids>
  CLI->>Parser: Parse args -> SuspendCommand(ID)
  CLI->>Ctl: executeSuspendCommand(ID)
  Ctl->>Ctl: Build ModifyTaskRequest{UID, TaskIds, Attribute=Suspend}
  Ctl->>RPC: ModifyTask(req)
  RPC->>Srv: gRPC ModifyTask
  Srv-->>RPC: Reply
  RPC-->>Ctl: Reply
  alt FlagJson set
    Ctl-->>User: Print JSON reply
  else
    Ctl-->>User: SummarizeReply
  end

  Note over Ctl: Resume flow mirrors Suspend with Attribute=Resume
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Potential focus areas:

  • internal/ccontrol/ccontrol.go: correctness of ModifyTaskRequest construction and error mapping.
  • Parser/dispatcher changes in internal/ccontrol/parser.go and internal/ccontrol/cmd.go: ensure action/ID extraction matches existing CLI conventions.
  • Protobuf enum value consistency (Suspend=3, Resume=4, Suspended=10) and generated code compatibility.

Possibly related PRs

Suggested reviewers

  • L-Xiafeng
  • Nativu5

Poem

I twitch my whiskers, tip my hat,
Pause the jobs where dormice nap,
When dawn arrives I give a hop —
Resume the queue, the spindles clap. 🥕🐇

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat: add TaskStatus Suspend' accurately reflects the main changes: adding a new TaskStatus enum member and related suspend/resume functionality.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

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: 0

🧹 Nitpick comments (2)
internal/ccontrol/ccontrol.go (2)

690-715: Consider aligning error handling with HoldReleaseJobs.

The error handling pattern differs from the similar HoldReleaseJobs function:

  1. Parse error handling: Uses log.Errorf + bare CraneError (lines 693-694), while HoldReleaseJobs returns a CraneError with a descriptive message.
  2. JSON mode error handling: Returns nil unconditionally (lines 709-712), while HoldReleaseJobs checks reply.NotModifiedTasks and returns an error code when appropriate.

Consider this alignment for consistency:

 func SuspendJobs(jobs string) error {
 	jobList, err := util.ParseJobIdList(jobs, ",")
 	if err != nil {
-		log.Errorf("invalid job list: %s", err)
-		return &util.CraneError{Code: util.ErrorCmdArg}
+		return &util.CraneError{
+			Code:    util.ErrorCmdArg,
+			Message: fmt.Sprintf("Invalid job list specified: %s.", err),
+		}
 	}

 	req := &protos.ModifyTaskRequest{
 		Uid:       uint32(os.Getuid()),
 		TaskIds:   jobList,
 		Attribute: protos.ModifyTaskRequest_Suspend,
 	}

 	reply, err := stub.ModifyTask(context.Background(), req)
 	if err != nil {
 		util.GrpcErrorPrintf(err, "Failed to suspend jobs")
 		return &util.CraneError{Code: util.ErrorNetwork}
 	}

 	if FlagJson {
 		fmt.Println(util.FmtJson.FormatReply(reply))
-		return nil
+		if len(reply.NotModifiedTasks) == 0 {
+			return nil
+		} else {
+			return &util.CraneError{Code: util.ErrorBackend}
+		}
 	}

 	return SummarizeReply(reply)
 }

717-742: Consider aligning error handling with HoldReleaseJobs.

The error handling pattern differs from the similar HoldReleaseJobs function:

  1. Parse error handling: Uses log.Errorf + bare CraneError (lines 720-721), while HoldReleaseJobs returns a CraneError with a descriptive message.
  2. JSON mode error handling: Returns nil unconditionally (lines 736-739), while HoldReleaseJobs checks reply.NotModifiedTasks and returns an error code when appropriate.

Consider this alignment for consistency:

 func ResumeJobs(jobs string) error {
 	jobList, err := util.ParseJobIdList(jobs, ",")
 	if err != nil {
-		log.Errorf("invalid job list: %s", err)
-		return &util.CraneError{Code: util.ErrorCmdArg}
+		return &util.CraneError{
+			Code:    util.ErrorCmdArg,
+			Message: fmt.Sprintf("Invalid job list specified: %s.", err),
+		}
 	}

 	req := &protos.ModifyTaskRequest{
 		Uid:       uint32(os.Getuid()),
 		TaskIds:   jobList,
 		Attribute: protos.ModifyTaskRequest_Resume,
 	}

 	reply, err := stub.ModifyTask(context.Background(), req)
 	if err != nil {
 		util.GrpcErrorPrintf(err, "Failed to resume jobs")
 		return &util.CraneError{Code: util.ErrorNetwork}
 	}

 	if FlagJson {
 		fmt.Println(util.FmtJson.FormatReply(reply))
-		return nil
+		if len(reply.NotModifiedTasks) == 0 {
+			return nil
+		} else {
+			return &util.CraneError{Code: util.ErrorBackend}
+		}
 	}

 	return SummarizeReply(reply)
 }
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 1606a8a and 794472b.

📒 Files selected for processing (7)
  • internal/ccontrol/ccontrol.go (1 hunks)
  • internal/ccontrol/cmd.go (2 hunks)
  • internal/ccontrol/help.go (1 hunks)
  • internal/ccontrol/parser.go (6 hunks)
  • internal/util/string.go (1 hunks)
  • protos/Crane.proto (1 hunks)
  • protos/PublicDefs.proto (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (3)
internal/ccontrol/cmd.go (2)
internal/util/err.go (3)
  • ErrorCmdArg (37-37)
  • ErrorGeneric (36-36)
  • ErrorSuccess (35-35)
internal/ccontrol/ccontrol.go (2)
  • SuspendJobs (690-715)
  • ResumeJobs (717-742)
internal/ccontrol/parser.go (1)
internal/cacctmgr/parser.go (3)
  • KeyValueParam (103-106)
  • ShowCommand (75-82)
  • DeleteCommand (43-49)
internal/ccontrol/ccontrol.go (5)
internal/util/string.go (1)
  • ParseJobIdList (1061-1073)
internal/util/err.go (3)
  • CraneError (44-47)
  • ErrorCmdArg (37-37)
  • ErrorNetwork (38-38)
internal/util/grpc.go (1)
  • GrpcErrorPrintf (388-399)
internal/ccontrol/cmd.go (1)
  • FlagJson (45-45)
internal/util/formatter.go (1)
  • FmtJson (58-58)

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: 1

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 69c59d4 and 9d2ea50.

📒 Files selected for processing (7)
  • internal/ccontrol/ccontrol.go (1 hunks)
  • internal/ccontrol/cmd.go (2 hunks)
  • internal/ccontrol/help.go (1 hunks)
  • internal/ccontrol/parser.go (6 hunks)
  • internal/util/string.go (1 hunks)
  • protos/Crane.proto (1 hunks)
  • protos/PublicDefs.proto (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (5)
  • protos/Crane.proto
  • protos/PublicDefs.proto
  • internal/ccontrol/parser.go
  • internal/util/string.go
  • internal/ccontrol/help.go
🧰 Additional context used
🧬 Code graph analysis (2)
internal/ccontrol/cmd.go (2)
internal/util/err.go (3)
  • ErrorCmdArg (36-36)
  • ErrorGeneric (35-35)
  • ErrorSuccess (34-34)
internal/ccontrol/ccontrol.go (2)
  • SuspendJobs (180-205)
  • ResumeJobs (207-232)
internal/ccontrol/ccontrol.go (5)
internal/util/string.go (1)
  • ParseJobIdList (1100-1112)
internal/util/err.go (3)
  • CraneError (43-47)
  • ErrorCmdArg (36-36)
  • ErrorNetwork (37-37)
internal/util/grpc.go (1)
  • GrpcErrorPrintf (387-398)
internal/ccontrol/cmd.go (1)
  • FlagJson (45-45)
internal/util/formatter.go (1)
  • FmtJson (58-58)

Comment on lines +199 to +204
if FlagJson {
fmt.Println(util.FmtJson.FormatReply(reply))
return nil
}

return SummarizeReply(reply)
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

Preserve JSON-mode failure signaling for suspend/resume.

When FlagJson is set, both paths return nil unconditionally. If the backend replies with NotModifiedTasks, ccontrol suspend --json or ccontrol resume --json will still exit 0, unlike other ModifyTask helpers (for example ChangeTaskTimeLimit and HoldReleaseJobs) that surface util.ErrorBackend. This silently hides partial failures from scripts relying on the exit status.

Mirror the existing pattern so JSON mode still returns an error when any task wasn’t modified.

  if FlagJson {
    fmt.Println(util.FmtJson.FormatReply(reply))
-   return nil
+   if len(reply.NotModifiedTasks) == 0 {
+     return nil
+   }
+   return &util.CraneError{Code: util.ErrorBackend}
  }

Apply the same guard to both SuspendJobs and ResumeJobs.

Also applies to: 226-231

🤖 Prompt for AI Agents
In internal/ccontrol/ccontrol.go around lines 199-204 and similarly 226-231, the
FlagJson branch prints the JSON reply then unconditionally returns nil; change
it to mirror the pattern used by other ModifyTask helpers so that after printing
the JSON you check the reply for backend/partial-failure (the NotModifiedTasks /
util.ErrorBackend condition) and return the corresponding error instead of nil
when any task wasn’t modified; in short, keep the JSON output but preserve
failure signaling by returning util.ErrorBackend (or the reply error) when the
reply indicates NotModifiedTasks/partial failure.

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