Skip to content

feat: Add scheduler that schedules tasks and garbage collect periodically - #37

Merged
sitaowang1998 merged 1 commit into
y-scope:mainfrom
sitaowang1998:scheduler
Dec 18, 2024
Merged

feat: Add scheduler that schedules tasks and garbage collect periodically#37
sitaowang1998 merged 1 commit into
y-scope:mainfrom
sitaowang1998:scheduler

Conversation

@sitaowang1998

@sitaowang1998 sitaowang1998 commented Dec 18, 2024

Copy link
Copy Markdown
Collaborator

Description

As title. Scheduler also send heartbeat message to storage periodcially.

Validation performed

  • GitHub workflows pass.
  • All unit tests pass in devcontainer.

Summary by CodeRabbit

  • New Features

    • Introduced a StopToken class for managing stop signals in a thread-safe manner.
    • Added methods for pausing and resuming the SchedulerServer.
    • Implemented new functionality for retrieving the local machine's IP address.
    • Enhanced command-line argument parsing and logging in the main application.
  • Bug Fixes

    • Improved error handling and logging in the SchedulerServer and heartbeat processes.
  • Documentation

    • Updated method signatures and class structures to reflect new functionalities.
  • Tests

    • Streamlined tests for SchedulerServer to directly control server state without threading complexity.

@coderabbitai

coderabbitai Bot commented Dec 18, 2024

Copy link
Copy Markdown
Contributor

Walkthrough

The pull request introduces several significant changes to the Spider project, focusing on enhancing the scheduler's functionality and control flow. A new StopToken utility is added to manage thread-safe stop requests across components. The SchedulerServer has been refactored to include pause and resume methods, and a new threading model. The main scheduler application now includes more robust error handling, command-line argument parsing, and background loops for heartbeat and cleanup operations.

Changes

File Change Summary
src/spider/CMakeLists.txt Added utils/StopToken.hpp to SPIDER_SCHEDULER_SOURCES, included Boost::program_options in target_link_libraries
src/spider/io/BoostAsio.hpp Added new get_address() method to resolve local machine IP address
src/spider/io/Serializer.hpp Updated serialization concepts, introducing Packable concept with more flexible packing operations
src/spider/scheduler/SchedulerServer.cpp Refactored constructor, added pause() and resume() methods, modified message receiving and thread management
src/spider/scheduler/SchedulerServer.hpp Updated class structure to support new threading and stop token management
src/spider/scheduler/scheduler.cpp Implemented main function with argument parsing, heartbeat loop, and cleanup loop
src/spider/utils/StopToken.hpp New file introducing thread-safe stop token management
tests/scheduler/test-SchedulerServer.cpp Updated test to use new StopToken and server control methods

Sequence Diagram

sequenceDiagram
    participant Main as Main Application
    participant Server as SchedulerServer
    participant Heartbeat as Heartbeat Loop
    participant Cleanup as Cleanup Loop
    participant Storage as Metadata/Data Storage

    Main->>Server: Initialize with StopToken
    Main->>Heartbeat: Start Heartbeat Loop
    Main->>Cleanup: Start Cleanup Loop
    
    loop Periodic Heartbeat
        Heartbeat->>Storage: Update Heartbeat
        alt Update Fails
            Heartbeat->>Main: Request Stop
        end
    end

    loop Periodic Cleanup
        Cleanup->>Server: Pause Server
        Cleanup->>Storage: Execute Cleanup Policy
        Cleanup->>Server: Resume Server
        alt Cleanup Fails
            Cleanup->>Main: Request Stop
        end
    end

    Main->>Server: Manage Server State
Loading

This sequence diagram illustrates the new control flow introduced in the scheduler, highlighting the interaction between the main application, server, heartbeat loop, cleanup loop, and storage components, with the StopToken enabling coordinated shutdown mechanisms.

Tip

CodeRabbit's docstrings feature is now available as part of our Early Access Program! Simply use the command @coderabbitai generate docstrings to have CodeRabbit automatically generate docstrings for your pull request. We would love to hear your feedback on Discord.


Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR. (Beta)
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

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

🧹 Nitpick comments (11)
src/spider/scheduler/SchedulerServer.cpp (2)

38-41: Safeguard concurrency in constructor thread creation
Spawning a new thread in the constructor can make debugging more difficult if exceptions are thrown outside. Ensure that any operations that might throw are completed prior to constructing a new thread. Otherwise, consider using a dedicated method to start the thread after construction is complete.


75-97: Handle persistent failure in acceptor
If repeated acceptance errors occur (e.g. ephemeral failure) or frequent exceptions are raised, consider implementing reconnection/backoff logic rather than immediately stopping the entire server.

🧰 Tools
🪛 cppcheck (2.10-2)

[performance] 88-88: Variable 'id' is assigned in constructor body. Consider performing initialization in initialization list.

(useInitializationList)

src/spider/scheduler/scheduler.cpp (4)

42-64: Validate command-line arguments
The parse_args function extracts port and storage_url. Confirm that the help message or usage instructions are displayed if these parameters are absent, as indicated in the code. You might consider providing default values or more robust error messages for a better user experience.


66-87: Heartbeat loop stoppage threshold
fail_count triggers a stop request after cRetryCount - 1. This offers limited attempts to recover from transitory errors. Adjust cRetryCount or add an exponential backoff if transient network issues may inadvertently stop the scheduler too frequently.


89-124: Cleanup loop logic
Pausing and resuming the server is a neat approach. However, ensure that no new tasks are accepted during the pause that might ultimately require resources that are being cleaned. Also, consider logging the cleanup outcome (number of cleaned items/number of dangling data removed) for diagnostic purposes.

🧰 Tools
🪛 cppcheck (2.10-2)

[performance] 107-107: Variable 'm_id' is assigned in constructor body. Consider performing initialization in initialization list.

(useInitializationList)


127-237: Main function thread management
Both the heartbeat and cleanup loops join at lines 229 and 230, then the server stops. If an exception is thrown before the joins, the threads might be left running. Consider wrapping these threads in RAII structures or adding more robust exception handling to guarantee threads are joined and the server is stopped.

src/spider/utils/StopToken.hpp (1)

9-15: Consider additional methods or conditions
stop_requested returns only a single boolean. If you foresee needing multiple reasons to stop or partial shutdown modes, you might generalize in the future (e.g., store an integer state or error code).

src/spider/scheduler/SchedulerServer.hpp (2)

29-30: Constructor parameter clarity
Adding the stop token parameter helps unify the lifecycle management. Update any inline documentation or comments to reflect why the constructor now requires a reference to core::StopToken.


51-53: Avoid referencing StopToken directly as a non-const reference
While it is valid, be aware that other code might inadvertently reset or mutate StopToken. If you prefer an immutable contract, consider storing std::shared_ptrcore::StopToken instead, so that ownership and references are more explicit.

src/spider/io/BoostAsio.hpp (1)

48-71: Consider enhancing the get_address() implementation

While the implementation is generally sound, consider these improvements:

  1. Add a timeout to the resolver to prevent hanging
  2. Consider adding IPv6 support for future-proofing
  3. Extract the warning message to a constant

Here's a suggested improvement:

 inline auto get_address() -> std::optional<std::string> {
+    static constexpr auto RESOLVER_TIMEOUT = std::chrono::seconds(5);
+    static constexpr auto WARNING_MSG = "No non-loopback address found, using loopback address";
     try {
         boost::asio::io_context io_context;
         boost::asio::ip::tcp::resolver resolver(io_context);
+        auto timer = boost::asio::steady_timer(io_context, RESOLVER_TIMEOUT);
+        timer.async_wait([&io_context](auto const& ec) {
+            if (!ec) { io_context.stop(); }
+        });
         auto const endpoints = resolver.resolve(boost::asio::ip::host_name(), "");
         for (auto const& endpoint : endpoints) {
             if (endpoint.endpoint().address().is_v4()
                 && !endpoint.endpoint().address().is_loopback())
             {
                 return endpoint.endpoint().address().to_string();
             }
         }
-        spdlog::warn("No non-loopback address found, using loopback address");
+        spdlog::warn(WARNING_MSG);
         for (auto const& endpoint : endpoints) {
             if (endpoint.endpoint().address().is_v4()) {
                 return endpoint.endpoint().address().to_string();
             }
         }
         return std::nullopt;
     } catch (boost::system::system_error const& e) {
+        spdlog::error("Failed to resolve address: {}", e.what());
         return std::nullopt;
     }
 }
tests/scheduler/test-SchedulerServer.cpp (1)

51-53: Consider enhancing lifecycle test coverage

While the basic pause/resume operations are tested, consider adding test cases for:

  • Multiple pause/resume cycles
  • Verifying operations are blocked during paused state
  • Error handling during state transitions

Example test cases to add:

// Test multiple pause/resume cycles
server.pause();
server.resume();
server.pause();
server.resume();

// Test operations during paused state
server.pause();
// Attempt operations, verify they're blocked
server.resume();

// Test error handling
server.pause();
server.pause(); // Should handle double pause gracefully
server.resume();
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 38297fc and a19cca4.

📒 Files selected for processing (8)
  • src/spider/CMakeLists.txt (2 hunks)
  • src/spider/io/BoostAsio.hpp (3 hunks)
  • src/spider/io/Serializer.hpp (1 hunks)
  • src/spider/scheduler/SchedulerServer.cpp (3 hunks)
  • src/spider/scheduler/SchedulerServer.hpp (3 hunks)
  • src/spider/scheduler/scheduler.cpp (1 hunks)
  • src/spider/utils/StopToken.hpp (1 hunks)
  • tests/scheduler/test-SchedulerServer.cpp (2 hunks)
🧰 Additional context used
🪛 cppcheck (2.10-2)
src/spider/scheduler/SchedulerServer.cpp

[performance] 88-88: Variable 'id' is assigned in constructor body. Consider performing initialization in initialization list.

(useInitializationList)

src/spider/scheduler/scheduler.cpp

[performance] 88-88: Variable 'id' is assigned in constructor body. Consider performing initialization in initialization list.

(useInitializationList)


[performance] 107-107: Variable 'm_id' is assigned in constructor body. Consider performing initialization in initialization list.

(useInitializationList)

🔇 Additional comments (10)
src/spider/scheduler/SchedulerServer.cpp (2)

43-50: Pause method concurrency
The pause method correctly stops the io_context and joins the thread. However, confirm that no new asynchronous operations are posted after the context is stopped, as that might cause race conditions or logic errors. Consider documenting the concurrency assumptions explicitly.


30-31: Ensure consistent handling of the new stop token parameter
The addition of the stop token parameter is good for clean shutdown logic. However, ensure that all instantiations of SchedulerServer have been updated accordingly elsewhere in the codebase. If any older constructor calls remain, they may cause a compile-time error.

✅ Verification successful

Let me search for actual instantiations of SchedulerServer to verify if there are any constructor calls that need updating.


Let me try one more search strategy to find any instantiations of SchedulerServer.


Let me check the test file and scheduler.cpp which might contain instantiations.


No issues found with stop_token parameter usage
Based on the code examination, all instantiations of SchedulerServer properly include the stop_token parameter. The only two instances found are in the test file and main scheduler implementation, both correctly using the new constructor signature with all required parameters including the stop_token.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Searching for all instantiations of SchedulerServer to verify constructor calls
rg -A 5 $'SchedulerServer\\('

Length of output: 1603


Script:

#!/bin/bash
# Search for actual instantiations of SchedulerServer using AST pattern matching
ast-grep --pattern 'new SchedulerServer($$$)'

# Also search for variable declarations that might instantiate SchedulerServer
ast-grep --pattern 'SchedulerServer $_ = $$$'
ast-grep --pattern 'auto $_ = SchedulerServer($$$)'

# Backup with ripgrep to catch any other potential instantiations
rg -B 2 -A 2 'SchedulerServer\s+\w+\s*\('
rg -B 2 -A 2 'new\s+SchedulerServer\s*\('

Length of output: 237


Script:

#!/bin/bash
# Search for files that might contain SchedulerServer instantiations
fd -e cpp -e hpp -e cc -e h | xargs rg -l "SchedulerServer"

# Then examine the content of these files
fd -e cpp -e hpp -e cc -e h | xargs rg -B 5 -A 5 "std::make_unique<SchedulerServer>|std::make_shared<SchedulerServer>|SchedulerServer\s*\w+\s*{"

Length of output: 614


Script:

#!/bin/bash
# Check the test file and scheduler.cpp for instantiations
cat tests/scheduler/test-SchedulerServer.cpp
cat src/spider/scheduler/scheduler.cpp

Length of output: 12683

src/spider/utils/StopToken.hpp (1)

7-20: Thread-safe stop mechanism
This new class offers a straightforward approach to stopping threads. Good use of std::atomic ensures there is no data race on stop token checks.

src/spider/scheduler/SchedulerServer.hpp (1)

33-34: New pause/resume methods
These methods simplify controlling io_context without externally manipulating threads. This approach improves readability by clearly separating the lifecycle states of the server.

src/spider/io/Serializer.hpp (2)

44-48: Well-designed template concept for flexible serialization

The new Packable concept provides a more flexible approach by parameterizing both the buffer type and the serializable type. This design enables better type safety and extensibility.


51-53: Verify backward compatibility of SerializableImpl changes

The redefinition of SerializableImpl to use Packable with msgpack::sbuffer is a good abstraction. However, we should verify existing implementations aren't affected.

✅ Verification successful

SerializableImpl changes are safe to proceed

The redefinition of SerializableImpl using Packable<msgpack::sbuffer, T> is backward compatible based on the following evidence:

  1. SerializableImpl is only used internally within Serializer.hpp to define the higher-level Serializable concept
  2. The only direct usage of Serializable is in TaskIo concept in src/spider/client/task.hpp
  3. All existing implementations already use msgpack::pack with msgpack::sbuffer as shown in the codebase scan
  4. The change formalizes the existing pattern that's already in use throughout the codebase
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for existing SerializableImpl implementations
rg -l "SerializableImpl" --type cpp --type hpp

Length of output: 74


Script:

#!/bin/bash
# Search for SerializableImpl usage with ripgrep, including all text files
rg -l "SerializableImpl"

# Also search for any Packable usage to understand impact
rg -l "Packable"

Length of output: 99


Script:

#!/bin/bash
# Get full context around SerializableImpl and Packable usage
rg "SerializableImpl|Packable" -C 5 src/spider/io/Serializer.hpp

Length of output: 555


Script:

#!/bin/bash
# Search for any usage of Serializable concept to understand impact on implementations
rg "Serializable\s*<" -C 3

# Also look for any msgpack::pack usage to find actual implementations
rg "msgpack::pack" -C 3

Length of output: 7756

src/spider/CMakeLists.txt (2)

102-102: LGTM: StopToken.hpp addition

The addition of StopToken.hpp aligns with the scheduler enhancement objectives.


114-114: Verify program_options usage

The addition of Boost::program_options is appropriate. Let's verify its usage in the scheduler component.

✅ Verification successful

Boost::program_options is correctly used in the scheduler component

The scheduler component properly includes and utilizes Boost.Program_options through:

  • Complete set of necessary header inclusions
  • Proper command-line argument parsing implementation in parse_args
  • Appropriate error handling for program options parsing
  • Consistent usage of program_options types and functions
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for program_options usage in scheduler files
rg "program_options" src/spider/scheduler/

Length of output: 1414

tests/scheduler/test-SchedulerServer.cpp (2)

24-24: LGTM: Header inclusion is properly placed

The StopToken header is correctly included with other project headers.


47-49: LGTM: Proper initialization order and RAII compliance

The StopToken is correctly instantiated before server creation and passed to the constructor.

Let's verify the constructor signature consistency:

✅ Verification successful

Constructor signature matches the test initialization

The constructor signature in src/spider/scheduler/SchedulerServer.cpp perfectly aligns with the test initialization, confirming proper parameter ordering:

  • port
  • policy
  • metadata_store
  • data_store
  • stop_token (passed by reference)
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify SchedulerServer constructor signature across codebase
ast-grep --pattern 'SchedulerServer($$$, stop_token)' 

Length of output: 55


Script:

#!/bin/bash
# Search for SchedulerServer constructor definition
ast-grep --pattern 'SchedulerServer::SchedulerServer($$$)'

# Also search for the class definition to understand the constructor declaration
ast-grep --pattern 'class SchedulerServer {
  $$$
}'

# Backup search using ripgrep for constructor
rg "SchedulerServer::SchedulerServer" -A 5

Length of output: 676

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