-
Notifications
You must be signed in to change notification settings - Fork 12
feat: Add scheduler server that listens and responds to schedule task requests #33
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
9 commits
Select commit
Hold shift + click to select a range
d29e81b
Add scheduler messages
sitaowang1998 4c2c249
Merge scheduler requests into one
sitaowang1998 36f58d3
Add scheduler server
sitaowang1998 2524285
Set ready states for head tasks when job is added
sitaowang1998 46bfc71
Remove task submission from scheduler server
sitaowang1998 e8db45f
Add run and stop for scheduler server
sitaowang1998 92150ac
Add scheduler server test and fix server context stop
sitaowang1998 a87d5e3
Improve code based on code rabbit suggestion
sitaowang1998 5532a97
Remove change to test-tasks.yaml for concurrent storage tests
sitaowang1998 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,56 @@ | ||
| #ifndef SPIDER_SCHEDULER_SCHEDULERMESSAGE_HPP | ||
| #define SPIDER_SCHEDULER_SCHEDULERMESSAGE_HPP | ||
|
|
||
| #include <optional> | ||
| #include <string> | ||
| #include <utility> | ||
|
|
||
| #include <boost/uuid/uuid.hpp> | ||
|
|
||
| #include "../io/MsgPack.hpp" // IWYU pragma: keep | ||
| #include "../io/Serializer.hpp" // IWYU pragma: keep | ||
|
|
||
| namespace spider::scheduler { | ||
|
|
||
| class ScheduleTaskRequest { | ||
| public: | ||
| /** | ||
| * Default constructor for msgpack. Do __not__ use it directly. | ||
| */ | ||
| ScheduleTaskRequest() = default; | ||
|
|
||
| ScheduleTaskRequest(boost::uuids::uuid const worker_id, std::string addr) | ||
| : m_worker_id{worker_id}, | ||
| m_worker_addr{std::move(addr)} {} | ||
|
|
||
| [[nodiscard]] auto get_worker_id() const -> boost::uuids::uuid { return m_worker_id; } | ||
|
|
||
| [[nodiscard]] auto get_worker_addr() const -> std::string const& { return m_worker_addr; } | ||
|
|
||
| MSGPACK_DEFINE_ARRAY(m_worker_id, m_worker_addr); | ||
|
|
||
| private: | ||
| boost::uuids::uuid m_worker_id; | ||
| std::string m_worker_addr; | ||
| }; | ||
|
|
||
| class ScheduleTaskResponse { | ||
| public: | ||
| ScheduleTaskResponse() = default; | ||
|
|
||
| explicit ScheduleTaskResponse(boost::uuids::uuid const task_id) : m_task_id{task_id} {} | ||
|
|
||
| [[nodiscard]] auto has_task_id() const -> bool { return m_task_id.has_value(); } | ||
|
|
||
| // NOLINTNEXTLINE(bugprone-unchecked-optional-access) | ||
| [[nodiscard]] auto get_task_id() const -> boost::uuids::uuid { return m_task_id.value(); } | ||
|
|
||
| MSGPACK_DEFINE_ARRAY(m_task_id); | ||
|
|
||
| private: | ||
| std::optional<boost::uuids::uuid> m_task_id = std::nullopt; | ||
| }; | ||
|
|
||
| } // namespace spider::scheduler | ||
|
|
||
| #endif // SPIDER_SCHEDULER_SCHEDULERMESSAGE_HPP | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,133 @@ | ||
| #include "SchedulerServer.hpp" | ||
|
|
||
| #include <memory> | ||
| #include <mutex> | ||
| #include <optional> | ||
| #include <stdexcept> | ||
| #include <utility> | ||
|
|
||
| #include <boost/uuid/uuid.hpp> | ||
| #include <boost/uuid/uuid_io.hpp> | ||
| #include <spdlog/spdlog.h> | ||
|
|
||
| #include "../io/BoostAsio.hpp" // IWYU pragma: keep | ||
| #include "../io/MsgPack.hpp" // IWYU pragma: keep | ||
| #include "../io/msgpack_message.hpp" | ||
| #include "../io/Serializer.hpp" // IWYU pragma: keep | ||
| #include "../storage/DataStorage.hpp" | ||
| #include "../storage/MetadataStorage.hpp" | ||
| #include "SchedulerMessage.hpp" | ||
| #include "SchedulerPolicy.hpp" | ||
|
|
||
| namespace spider::scheduler { | ||
|
|
||
| SchedulerServer::SchedulerServer( | ||
| unsigned short const port, | ||
| std::shared_ptr<SchedulerPolicy> policy, | ||
| std::shared_ptr<core::MetadataStorage> metadata_store, | ||
| std::shared_ptr<core::DataStorage> data_store | ||
| ) | ||
| : m_acceptor{m_context, {boost::asio::ip::tcp::v4(), port}}, | ||
| m_policy{std::move(policy)}, | ||
| m_metadata_store{std::move(metadata_store)}, | ||
| m_data_store{std::move(data_store)} { | ||
| // Ignore the returned future as we do not need its value | ||
| boost::asio::co_spawn(m_context, receive_message(), boost::asio::use_future); | ||
| } | ||
|
|
||
| auto SchedulerServer::run() -> void { | ||
| m_context.run(); | ||
| } | ||
|
|
||
| auto SchedulerServer::stop() -> void { | ||
| m_context.stop(); | ||
| std::lock_guard const lock{m_mutex}; | ||
| m_stop = true; | ||
| } | ||
|
|
||
| auto SchedulerServer::receive_message() -> boost::asio::awaitable<void> { | ||
| while (!should_stop()) { | ||
| // std::unique_ptr<boost::asio::ip::tcp::socket> socket | ||
| // = std::make_unique<boost::asio::ip::tcp::socket>(m_context); | ||
| boost::asio::ip::tcp::socket socket{m_context}; | ||
| auto const& [ec] = co_await m_acceptor.async_accept( | ||
| socket, | ||
| boost::asio::as_tuple(boost::asio::use_awaitable) | ||
| ); | ||
| if (ec) { | ||
| spdlog::error("Cannot accept connection {}: {}", ec.value(), ec.what()); | ||
| continue; | ||
| } | ||
| // Ignore the returned future as we do not need its value | ||
| boost::asio::co_spawn( | ||
| m_context, | ||
| process_message(std::move(socket)), | ||
| boost::asio::use_future | ||
| ); | ||
| } | ||
| co_return; | ||
| } | ||
|
|
||
| namespace { | ||
| auto deserialize_message(msgpack::sbuffer const& buffer) -> std::optional<ScheduleTaskRequest> { | ||
| try { | ||
| msgpack::object_handle const handle = msgpack::unpack(buffer.data(), buffer.size()); | ||
| msgpack::object const object = handle.get(); | ||
| return object.as<ScheduleTaskRequest>(); | ||
| } catch (std::runtime_error& e) { | ||
| spdlog::error("Cannot unpack message to ScheduleTaskRequest: {}", e.what()); | ||
| return std::nullopt; | ||
| } | ||
| } | ||
| } // namespace | ||
|
|
||
| auto SchedulerServer::process_message(boost::asio::ip::tcp::socket socket | ||
| ) -> boost::asio::awaitable<void> { | ||
| // NOLINTBEGIN(clang-analyzer-core.CallAndMessage) | ||
| std::optional<msgpack::sbuffer> const& optional_message_buffer | ||
| = co_await core::receive_message_async(socket); | ||
| // NOLINTEND(clang-analyzer-core.CallAndMessage) | ||
|
|
||
| if (false == optional_message_buffer.has_value()) { | ||
| spdlog::error("Cannot receive message from worker"); | ||
| co_return; | ||
| } | ||
| msgpack::sbuffer const& message_buffer = optional_message_buffer.value(); | ||
| std::optional<ScheduleTaskRequest> const& optional_request | ||
| = deserialize_message(message_buffer); | ||
| if (false == optional_request.has_value()) { | ||
| spdlog::error("Cannot parse message into schedule task request"); | ||
| co_return; | ||
| } | ||
| ScheduleTaskRequest const& request = optional_request.value(); | ||
|
|
||
| std::optional<boost::uuids::uuid> const task_id = m_policy->schedule_next( | ||
| m_metadata_store, | ||
| m_data_store, | ||
| request.get_worker_id(), | ||
| request.get_worker_addr() | ||
| ); | ||
| ScheduleTaskResponse response{}; | ||
| if (task_id.has_value()) { | ||
| response = ScheduleTaskResponse{task_id.value()}; | ||
| } | ||
| msgpack::sbuffer response_buffer; | ||
| msgpack::pack(response_buffer, response); | ||
|
|
||
| bool const success = co_await core::send_message_async(socket, response_buffer); | ||
| if (!success) { | ||
| spdlog::error( | ||
| "Cannot send message to worker {} at {}", | ||
| boost::uuids::to_string(request.get_worker_id()), | ||
| request.get_worker_addr() | ||
| ); | ||
| } | ||
| co_return; | ||
| } | ||
|
|
||
| auto SchedulerServer::should_stop() -> bool { | ||
| std::lock_guard const lock{m_mutex}; | ||
| return m_stop; | ||
| } | ||
|
|
||
| } // namespace spider::scheduler |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,57 @@ | ||
| #ifndef SPIDER_SCHEDULER_SCHEDULERSERVER_HPP | ||
| #define SPIDER_SCHEDULER_SCHEDULERSERVER_HPP | ||
|
|
||
| #include <memory> | ||
| #include <mutex> | ||
|
|
||
| #include "../io/BoostAsio.hpp" // IWYU pragma: keep | ||
| #include "../storage/DataStorage.hpp" | ||
| #include "../storage/MetadataStorage.hpp" | ||
| #include "SchedulerPolicy.hpp" | ||
|
|
||
| namespace spider::scheduler { | ||
|
|
||
| class SchedulerServer { | ||
| public: | ||
| // Delete copy & move constructor and assignment operator | ||
| SchedulerServer(SchedulerServer const&) = delete; | ||
| auto operator=(SchedulerServer const&) -> SchedulerServer& = delete; | ||
| SchedulerServer(SchedulerServer&&) = delete; | ||
| auto operator=(SchedulerServer&&) noexcept -> SchedulerServer& = delete; | ||
| ~SchedulerServer() = default; | ||
|
|
||
| SchedulerServer( | ||
| unsigned short port, | ||
| std::shared_ptr<SchedulerPolicy> policy, | ||
| std::shared_ptr<core::MetadataStorage> metadata_store, | ||
| std::shared_ptr<core::DataStorage> data_store | ||
| ); | ||
|
|
||
| /** | ||
| * Run the server loop. This function blocks until stop is called. | ||
| */ | ||
| auto run() -> void; | ||
|
|
||
| auto stop() -> void; | ||
|
|
||
| private: | ||
| auto receive_message() -> boost::asio::awaitable<void>; | ||
|
|
||
| auto process_message(boost::asio::ip::tcp::socket socket) -> boost::asio::awaitable<void>; | ||
|
|
||
| auto should_stop() -> bool; | ||
|
|
||
| std::shared_ptr<SchedulerPolicy> m_policy; | ||
| std::shared_ptr<core::MetadataStorage> m_metadata_store; | ||
| std::shared_ptr<core::DataStorage> m_data_store; | ||
|
|
||
| boost::asio::io_context m_context; | ||
| boost::asio::ip::tcp::acceptor m_acceptor; | ||
|
|
||
| std::mutex m_mutex; | ||
| bool m_stop = false; | ||
| }; | ||
|
|
||
| } // namespace spider::scheduler | ||
|
|
||
| #endif // SPIDER_SCHEDULER_SCHEDULERSERVER_HPP |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Document or handle potential std::optional::value() exception
The
get_task_id()method could throw ifm_task_idis empty. Consider either:📝 Committable suggestion