Skip to content

Conversation

mxsm
Copy link
Owner

@mxsm mxsm commented Sep 11, 2025

Which Issue(s) This PR Fixes(Closes)

Fixes #4014

Brief Description

How Did You Test This Change?

Summary by CodeRabbit

  • New Features

    • None.
  • Bug Fixes

    • Startup now fails fast with clear error messages when initialization or configuration loading encounters issues, instead of silently continuing.
    • Prevents crashes by removing unsafe unwraps during configuration decoding.
  • Refactor

    • Unified, consistent error handling across NameServer startup and configuration loading to improve reliability and observability for operators.

@Copilot Copilot AI review requested due to automatic review settings September 11, 2025 03:24
Copy link
Contributor

coderabbitai bot commented Sep 11, 2025

Walkthrough

Refactors nameserver startup to propagate errors using RocketMQResult. main awaits boot and returns errors. NameServerBootstrap::boot and NameServerRuntime::initialize now return RocketMQResult and use ? to propagate failures. KVConfigManager::load returns RocketMQResult, switches to decode via RemotingDeserializable, and propagates decode errors.

Changes

Cohort / File(s) Summary
Startup error propagation
rocketmq-namesrv/src/bin/namesrv_bootstrap_server.rs, rocketmq-namesrv/src/bootstrap.rs
main awaits boot and propagates errors. NameServerBootstrap::boot -> RocketMQResult<()>; NameServerRuntime::initialize -> RocketMQResult<()>; initialize/load_config use ?; boot returns Ok(()) after join.
KV config load result + deserialization
rocketmq-namesrv/src/kvconfig/kvconfig_mananger.rs
KVConfigManager::load -> RocketMQResult<()>; replaces SerdeJsonUtils::decode(...).unwrap() with KVConfigSerializeWrapper::decode(...)? using RemotingDeserializable; propagates decode errors; imports updated.

Sequence Diagram(s)

sequenceDiagram
  actor CLI as Process
  participant Main as namesrv_bootstrap_server::main
  participant Boot as NameServerBootstrap::boot()
  participant Runtime as NameServerRuntime::initialize()
  participant KV as KVConfigManager::load()

  CLI->>Main: start
  Main->>Boot: await boot()
  Boot->>Runtime: await initialize()
  Runtime->>KV: load()
  alt decode/read OK
    KV-->>Runtime: Ok(())
    Runtime-->>Boot: Ok(())
    Boot-->>Main: Ok(())
    Main-->>CLI: Ok(()) exit 0
  else error
    KV-->>Runtime: Err(e)
    Runtime-->>Boot: Err(e)
    Boot-->>Main: Err(e)
    Main-->>CLI: Err(e) exit non-zero
  end

  note over Boot,Runtime: Errors propagate via RocketMQResult and ?
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Pre-merge checks (4 passed, 1 inconclusive)

❌ Failed checks (1 inconclusive)
Check name Status Explanation Resolution
Linked Issues Check ❓ Inconclusive The PR implements the core coding objective by changing async function signatures to return RocketMQResult and propagating errors in namesrv_bootstrap_server.rs, bootstrap.rs, and kvconfig_mananger.rs (boot, initialize, and load signatures were updated). However, the PR/summary contains no evidence of updated unit tests, CI/test results, or verification that all callers were updated and that no regressions or performance impacts were introduced, so I cannot confirm full compliance with the linked issue checklist. Recommend adding or updating unit and integration tests that exercise the new error paths, running CI/build to show all callers compile and handle RocketMQResult, and including a short verification note or test output in the PR so reviewers can confirm no regressions.
✅ Passed checks (4 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 primary change—refactoring async functions to return RocketMQResult for improved error handling—and matches edits in namesrv_bootstrap_server.rs, bootstrap.rs, and kvconfig_mananger.rs that update signatures and propagate errors; it also references the linked issue #4014. It is concise and clear for a reviewer, though the emoji and issue tag are minor noise.
Out of Scope Changes Check ✅ Passed Based on the provided summaries, all code changes are focused on the stated refactor (switching async functions to return RocketMQResult and propagating errors) and related deserialization error handling in KVConfigManager, with no unrelated features or modules modified. The deserialization change aligns with improved error propagation and appears in-scope.
Docstring Coverage ✅ Passed No functions found in the changes. Docstring coverage check skipped.

Poem

I nibbled on configs by moonlit byte,
Swapped unwraps for results—much safer at night.
With ? I hop, from burrow to sky,
If errors appear, I squeak and comply.
Now boots don’t bluff, they tell it outright—
A tidy warren, and greener flight. 🐇✨

Tip

👮 Agentic pre-merge checks are now available in preview!

Pro plan users can now enable pre-merge checks in their settings to enforce checklists before merging PRs.

  • Built-in checks – Quickly apply ready-made checks to enforce title conventions, require pull request descriptions that follow templates, validate linked issues for compliance, and more.
  • Custom agentic checks – Define your own rules using CodeRabbit’s advanced agentic capabilities to enforce organization-specific policies and workflows. For example, you can instruct CodeRabbit’s agent to verify that API documentation is updated whenever API schema files are modified in a PR. Note: Upto 5 custom checks are currently allowed during the preview period. Pricing for this feature will be announced in a few weeks.

Please see the documentation for more information.

Example:

reviews:
  pre_merge_checks:
    custom_checks:
      - name: "Undocumented Breaking Changes"
        mode: "warning"
        instructions: |
          Pass/fail criteria: All breaking changes to public APIs, CLI flags, environment variables, configuration keys, database schemas, or HTTP/GraphQL endpoints must be documented in the "Breaking Change" section of the PR description and in CHANGELOG.md. Exclude purely internal or private changes (e.g., code not exported from package entry points or explicitly marked as internal).

Please share your feedback with us on this Discord post.

✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch refactor-4014

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.

@rocketmq-rust-bot
Copy link
Collaborator

🔊@mxsm 🚀Thanks for your contribution🎉!

💡CodeRabbit(AI) will review your code first🔥!

Note

🚨The code review suggestions from CodeRabbit are to be used as a reference only, and the PR submitter can decide whether to make changes based on their own judgment. Ultimately, the project management personnel will conduct the final code review💥.

Copy link
Contributor

@Copilot Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull Request Overview

This PR refactors async functions in the RocketMQ Namesrv component to return RocketMQResult<()> for better error handling instead of returning () and using unwrap() calls.

  • Replaces unwrap() calls with proper error propagation using the ? operator
  • Updates function signatures to return RocketMQResult<()> for consistent error handling
  • Removes dependency on SerdeJsonUtils in favor of direct deserialization methods

Reviewed Changes

Copilot reviewed 2 out of 3 changed files in this pull request and generated 1 comment.

File Description
rocketmq-namesrv/src/kvconfig/kvconfig_mananger.rs Updates load() method to return RocketMQResult<()> and replaces unwrap() with proper error handling
rocketmq-namesrv/src/bootstrap.rs Updates bootstrap methods to return RocketMQResult<()> and propagate errors using ? operator

Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.

Comment on lines +94 to 99
let wrapper = KVConfigSerializeWrapper::decode(content.as_bytes())?;
if let Some(config_table) = wrapper.config_table {
for (key, value) in config_table {
self.config_table.insert(key, value);
}
info!("load KV config success");
Copy link

Copilot AI Sep 11, 2025

Choose a reason for hiding this comment

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

The change from SerdeJsonUtils::decode() to KVConfigSerializeWrapper::decode() may introduce a breaking change if the deserialization behavior differs. Ensure that KVConfigSerializeWrapper::decode() provides the same error handling and deserialization logic as the previous implementation.

Suggested change
let wrapper = KVConfigSerializeWrapper::decode(content.as_bytes())?;
if let Some(config_table) = wrapper.config_table {
for (key, value) in config_table {
self.config_table.insert(key, value);
}
info!("load KV config success");
match KVConfigSerializeWrapper::decode(content.as_bytes()) {
Ok(wrapper) => {
if let Some(config_table) = wrapper.config_table {
for (key, value) in config_table {
self.config_table.insert(key, value);
}
info!("load KV config success");
}
}
Err(e) => {
error!("Failed to deserialize KV config: {:?}", e);
return Err(e.into());
}

Copilot uses AI. Check for mistakes.

Copy link

codecov bot commented Sep 11, 2025

Codecov Report

❌ Patch coverage is 0% with 13 lines in your changes missing coverage. Please review.
✅ Project coverage is 26.58%. Comparing base (fd71c20) to head (f5adf3b).
⚠️ Report is 1 commits behind head on main.

Files with missing lines Patch % Lines
rocketmq-namesrv/src/bootstrap.rs 0.00% 9 Missing ⚠️
rocketmq-namesrv/src/kvconfig/kvconfig_mananger.rs 0.00% 3 Missing ⚠️
...cketmq-namesrv/src/bin/namesrv_bootstrap_server.rs 0.00% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #4015      +/-   ##
==========================================
- Coverage   26.58%   26.58%   -0.01%     
==========================================
  Files         565      565              
  Lines       80699    80703       +4     
==========================================
  Hits        21453    21453              
- Misses      59246    59250       +4     

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

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Copy link
Collaborator

@rocketmq-rust-bot rocketmq-rust-bot left a comment

Choose a reason for hiding this comment

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

LGTM

@rocketmq-rust-bot rocketmq-rust-bot merged commit 3a76306 into main Sep 11, 2025
22 of 23 checks passed
@rocketmq-rust-bot rocketmq-rust-bot added approved PR has approved and removed ready to review waiting-review waiting review this PR labels Sep 11, 2025
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

🧹 Nitpick comments (2)
rocketmq-namesrv/src/kvconfig/kvconfig_mananger.rs (1)

117-121: Avoid panic on serialization during persist()

serde_json::to_string(...).unwrap() can panic; handle the error and log instead to keep the process stable.

-        let content = serde_json::to_string(&wrapper).unwrap();
+        let content = match serde_json::to_string(&wrapper) {
+            Ok(s) => s,
+            Err(e) => {
+                error!("serialize KV config failed: {}", e);
+                return;
+            }
+        };
rocketmq-namesrv/src/bootstrap.rs (1)

90-98: Make load_config synchronous (no awaits) to simplify the init path

load_config performs no async work; make it sync and drop the unnecessary .await in initialize for clarity and less boilerplate.

-    pub async fn initialize(&mut self) -> RocketMQResult<()> {
-        self.load_config().await?;
+    pub async fn initialize(&mut self) -> RocketMQResult<()> {
+        self.load_config()?;
         self.initiate_network_components();
         self.register_processor();
         self.start_schedule_service();
         self.initiate_ssl_context();
         self.initiate_rpc_hooks();
         Ok(())
     }
 
-    async fn load_config(&mut self) -> RocketMQResult<()> {
+    fn load_config(&mut self) -> RocketMQResult<()> {
         if let Some(kv_config_manager) = self.inner.kvconfig_manager.as_mut() {
             kv_config_manager.load()?;
         }
         Ok(())
     }

Also applies to: 100-105

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between fd71c20 and f5adf3b.

📒 Files selected for processing (3)
  • rocketmq-namesrv/src/bin/namesrv_bootstrap_server.rs (1 hunks)
  • rocketmq-namesrv/src/bootstrap.rs (3 hunks)
  • rocketmq-namesrv/src/kvconfig/kvconfig_mananger.rs (2 hunks)
🧰 Additional context used
🧬 Code graph analysis (2)
rocketmq-namesrv/src/kvconfig/kvconfig_mananger.rs (3)
rocketmq-common/src/utils/file_utils.rs (1)
  • file_to_string (30-37)
rocketmq-remoting/src/protocol.rs (2)
  • decode (464-464)
  • decode (485-487)
rocketmq-common/src/utils/serde_json_utils.rs (1)
  • decode (21-26)
rocketmq-namesrv/src/bootstrap.rs (3)
rocketmq-broker/src/broker_bootstrap.rs (4)
  • boot (32-41)
  • start (47-49)
  • wait_for_signal_inner (52-60)
  • initialize (43-45)
rocketmq-remoting/src/clients/client.rs (1)
  • tokio (251-251)
rocketmq-remoting/src/net/channel.rs (1)
  • tokio (221-221)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (9)
  • GitHub Check: build
  • GitHub Check: test
  • GitHub Check: build (ubuntu-latest, nightly)
  • GitHub Check: build (windows-latest, nightly)
  • GitHub Check: build (windows-latest, stable)
  • GitHub Check: build (macos-latest, nightly)
  • GitHub Check: build (macos-latest, stable)
  • GitHub Check: build (ubuntu-latest, stable)
  • GitHub Check: auto-approve
🔇 Additional comments (3)
rocketmq-namesrv/src/kvconfig/kvconfig_mananger.rs (1)

23-26: Imports align with the new result-based flow

Adding RocketMQResult and RemotingDeserializable is correct and consistent with the PR objective.

rocketmq-namesrv/src/bin/namesrv_bootstrap_server.rs (1)

62-64: Good: propagate boot errors to main

Using .await? ensures startup failures surface to the process exit code.

rocketmq-namesrv/src/bootstrap.rs (1)

66-75: Boot now returns RocketMQResult — OK

Clear propagation of initialization errors, then graceful shutdown via join; returning Ok(()) is appropriate.

Comment on lines +86 to 103
pub fn load(&mut self) -> RocketMQResult<()> {
let result = FileUtils::file_to_string(
self.name_server_runtime_inner
.name_server_config()
.kv_config_path
.as_str(),
);
if let Ok(content) = result {
let wrapper =
SerdeJsonUtils::decode::<KVConfigSerializeWrapper>(content.as_bytes()).unwrap();
let wrapper = KVConfigSerializeWrapper::decode(content.as_bytes())?;
if let Some(config_table) = wrapper.config_table {
for (key, value) in config_table {
self.config_table.insert(key, value);
}
info!("load KV config success");
}
}
Ok(())
}
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

Propagate file I/O errors and skip decoding empty content to avoid startup failure

FileUtils::file_to_string returns Ok("") when the file doesn't exist; decoding an empty string will now error and bubble up, breaking boot. Also, actual I/O errors are currently swallowed. Propagate I/O errors, and early-return on empty content.

-    pub fn load(&mut self) -> RocketMQResult<()> {
-        let result = FileUtils::file_to_string(
-            self.name_server_runtime_inner
-                .name_server_config()
-                .kv_config_path
-                .as_str(),
-        );
-        if let Ok(content) = result {
-            let wrapper = KVConfigSerializeWrapper::decode(content.as_bytes())?;
-            if let Some(config_table) = wrapper.config_table {
-                for (key, value) in config_table {
-                    self.config_table.insert(key, value);
-                }
-                info!("load KV config success");
-            }
-        }
-        Ok(())
-    }
+    pub fn load(&mut self) -> RocketMQResult<()> {
+        let path = self
+            .name_server_runtime_inner
+            .name_server_config()
+            .kv_config_path
+            .as_str();
+        let content = FileUtils::file_to_string(path)?;
+        if content.trim().is_empty() {
+            // Missing or empty file is not an error; nothing to load.
+            return Ok(());
+        }
+        let wrapper = KVConfigSerializeWrapper::decode(content.as_bytes())?;
+        if let Some(config_table) = wrapper.config_table {
+            for (key, value) in config_table {
+                self.config_table.insert(key, value);
+            }
+            info!("load KV config success");
+        }
+        Ok(())
+    }
📝 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
pub fn load(&mut self) -> RocketMQResult<()> {
let result = FileUtils::file_to_string(
self.name_server_runtime_inner
.name_server_config()
.kv_config_path
.as_str(),
);
if let Ok(content) = result {
let wrapper =
SerdeJsonUtils::decode::<KVConfigSerializeWrapper>(content.as_bytes()).unwrap();
let wrapper = KVConfigSerializeWrapper::decode(content.as_bytes())?;
if let Some(config_table) = wrapper.config_table {
for (key, value) in config_table {
self.config_table.insert(key, value);
}
info!("load KV config success");
}
}
Ok(())
}
pub fn load(&mut self) -> RocketMQResult<()> {
let path = self
.name_server_runtime_inner
.name_server_config()
.kv_config_path
.as_str();
let content = FileUtils::file_to_string(path)?;
if content.trim().is_empty() {
// Missing or empty file is not an error; nothing to load.
return Ok(());
}
let wrapper = KVConfigSerializeWrapper::decode(content.as_bytes())?;
if let Some(config_table) = wrapper.config_table {
for (key, value) in config_table {
self.config_table.insert(key, value);
}
info!("load KV config success");
}
Ok(())
}
🤖 Prompt for AI Agents
In rocketmq-namesrv/src/kvconfig/kvconfig_mananger.rs around lines 86 to 103,
the current implementation swallows file I/O errors and attempts to decode an
empty string (which causes a startup failure); change the code to propagate I/O
errors by using the ? operator on FileUtils::file_to_string so real read errors
return early, then check if the returned content is empty and return Ok(()) (or
log and skip) before attempting to decode, and only call
KVConfigSerializeWrapper::decode when content is non-empty so decoding empty
content is avoided.

@mxsm mxsm deleted the refactor-4014 branch September 11, 2025 14:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

AI review first Ai review pr first approved PR has approved auto merge refactor♻️ refactor code

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Refactor♻️]Refactor: Update async functions to return RocketMQResult for better error handling

3 participants