Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
89 commits
Select commit Hold shift + click to select a range
a52c418
Add signal handler for SIGTERM and no-exit flag to install signal han…
sitaowang1998 Apr 7, 2025
5e99f86
Add error handling for installing signal handler
sitaowang1998 Apr 7, 2025
632d592
Add integration test for no exit
sitaowang1998 Apr 7, 2025
f7d8739
Fix test fixture not yielding values
sitaowang1998 Apr 7, 2025
ce95080
Reformat file
sitaowang1998 Apr 7, 2025
0f2753e
Fix typo
sitaowang1998 Apr 7, 2025
12a4145
Check stop token in fetcht task loop
sitaowang1998 Apr 7, 2025
eceb4d8
Add non-stop sleep when no_exit
sitaowang1998 Apr 7, 2025
7ebdea9
Refactor get task arguments into a separate function
sitaowang1998 Apr 7, 2025
010e56d
Unmark main as noreturn
sitaowang1998 Apr 7, 2025
0c55ded
Fix integration test typo
sitaowang1998 Apr 7, 2025
dea5a6f
Refactor get task arguments into a separate function
sitaowang1998 Apr 7, 2025
8c118ba
Rename function to avoid overload
sitaowang1998 Apr 8, 2025
a9f44a8
Rename args_buffer to arg_buffer
sitaowang1998 Apr 8, 2025
08ac7a9
Intercept SIGTERM in task executor
sitaowang1998 Apr 8, 2025
9d86398
Merge branch 'main' into worker_sigterm
sitaowang1998 Apr 8, 2025
1bf92cb
Reformat files
sitaowang1998 Apr 8, 2025
9be5b98
Add SIGTERM handler in scheduler to no_exit flag in scheduler
sitaowang1998 Apr 8, 2025
defe200
Rename global variable to avoid name shadowing
sitaowang1998 Apr 8, 2025
aa849ca
Fix clang tidy
sitaowang1998 Apr 8, 2025
115352a
Merge branch 'main' into worker_refactor
sitaowang1998 Apr 8, 2025
75a8544
Refactor task_loop to move setup and result handling out
sitaowang1998 Apr 8, 2025
b41e362
Merge branch 'worker_refactor' into worker_sigterm
sitaowang1998 Apr 9, 2025
7875aff
Fix task executor signal hanlder error handling
sitaowang1998 Apr 9, 2025
4a28913
Reinstall SIGTERM handler after user function completes
sitaowang1998 Apr 9, 2025
5897675
Worker resends signal to process group and update tests to start work…
sitaowang1998 Apr 9, 2025
3b88c28
Fix clang-tidy
sitaowang1998 Apr 9, 2025
cbaf131
Merge branch 'main' into worker_sigterm
sitaowang1998 Apr 11, 2025
f325c34
Add singleton stop token
sitaowang1998 Apr 11, 2025
0b7328a
Remove print in signal handler
sitaowang1998 Apr 11, 2025
6ebbd5d
Add task executor pid singleton and signal sending in handler
sitaowang1998 Apr 12, 2025
e8aaeb0
Add tests for task executor with signal handling
sitaowang1998 Apr 12, 2025
8195cf6
Use SIG_IGN
sitaowang1998 Apr 12, 2025
604d817
Add docstring
sitaowang1998 Apr 12, 2025
e247d1d
Fix the naming of function
sitaowang1998 Apr 12, 2025
180a2e2
Fix signal handler in test
sitaowang1998 Apr 12, 2025
f88d346
Use std::atomic_flag instead of std::sig_atomic_t for StopToken
sitaowang1998 Apr 12, 2025
7870a54
Add private constructor and delete copy constructor and operator for …
sitaowang1998 Apr 14, 2025
e77da9a
Add docstring for intergration tests
sitaowang1998 Apr 14, 2025
6b295a6
Delete move constructor and assignment for singleton class
sitaowang1998 Apr 14, 2025
9d1f889
Fix unit test that uses stop token
sitaowang1998 Apr 14, 2025
14ec7b2
Fix scheduler stop token
sitaowang1998 Apr 14, 2025
28c489b
Reformat code
sitaowang1998 Apr 14, 2025
ce278f0
Fix cmake signal test lib prefix
sitaowang1998 Apr 14, 2025
d69ad00
Remove no-exit flag and exit as if SIGTERM is not handled
sitaowang1998 Apr 14, 2025
f7c9fbb
Remove no-exit tests
sitaowang1998 Apr 14, 2025
3d03fd9
Remove unused no_exit variable in scheduler
sitaowang1998 Apr 14, 2025
a527b10
Use static variable for singleton pattern to avoid initialization in …
sitaowang1998 Apr 14, 2025
2d4cb2a
Revert "Use static variable for singleton pattern to avoid initializa…
sitaowang1998 Apr 14, 2025
385421c
Use sigaction instead of std::signal
sitaowang1998 Apr 14, 2025
2cc88fa
Rename stop_requested to is_stop_requested
sitaowang1998 Apr 14, 2025
3c0344f
Use static member variable for singleton pattern
sitaowang1998 Apr 14, 2025
fb30e65
Fix stop token in scheduler server
sitaowang1998 Apr 14, 2025
ed1a44f
Fix stop token in scheduler server
sitaowang1998 Apr 14, 2025
50be6ac
Fix clang tidy
sitaowang1998 Apr 14, 2025
43fa18f
Fix clang tidy
sitaowang1998 Apr 14, 2025
fd81e92
Fix clang tidy
sitaowang1998 Apr 14, 2025
b61ba60
Fix comment to ignore SIGTERM in worker.
sitaowang1998 Apr 17, 2025
63d70be
Fix comment for StopFlag.
sitaowang1998 Apr 17, 2025
ef53924
Fix comment for StopFlag in worker.
sitaowang1998 Apr 17, 2025
f178cf3
Rename StopToken to StopFlag
sitaowang1998 Apr 17, 2025
971bac4
Merge branch 'worker_sigterm' of github.com:sitaowang1998/spider into…
sitaowang1998 Apr 17, 2025
552b120
Add class docstring for StopFlag
sitaowang1998 Apr 17, 2025
26492b8
Add class docstring for ChildPid
sitaowang1998 Apr 17, 2025
55215c8
Delete constructor for singleton classes
sitaowang1998 Apr 17, 2025
bc9bbe4
Reformat code
sitaowang1998 Apr 17, 2025
0f115a1
Add check for worker exit code on SIGTERM and add more docstring for …
sitaowang1998 Apr 17, 2025
8998367
Rename StopToken to StopFlag in cmake
sitaowang1998 Apr 17, 2025
6551c2b
Remove unnecessary clang-tidy suppression in task executor
sitaowang1998 Apr 17, 2025
8745109
Remove unnecessary clang-tidy suppression in worker
sitaowang1998 Apr 17, 2025
3809b06
Use unique_ptr instead of shared_ptr to avoid unnecessary overhead.
sitaowang1998 Apr 17, 2025
8fe410e
Add job cleanup for signal integration tests.
sitaowang1998 Apr 17, 2025
7a11fd6
Task executor does not ignore SIGTERM by default.
sitaowang1998 Apr 17, 2025
daab477
Add integration test for default SIGTERM behavior.
sitaowang1998 Apr 17, 2025
0f0823c
Fix integration test for default SIGTERM behavior.
sitaowang1998 Apr 17, 2025
c81fa2c
Rename test file to solve typo and fix parent path
sitaowang1998 Apr 21, 2025
768f93c
Use available tcp port for scheduler instead of hard coded port
sitaowang1998 Apr 21, 2025
93d7f99
Use free tcp port for all integration tests and fix name shadowning
sitaowang1998 Apr 21, 2025
99db683
Fix scheduler port
sitaowang1998 Apr 21, 2025
e55de6c
Merge branch 'worker_sigterm' of github.com:sitaowang1998/spider into…
sitaowang1998 Apr 21, 2025
f3b9ff9
Fix job clenaup in tests
sitaowang1998 Apr 21, 2025
a6de071
Fix comment typo.
sitaowang1998 Apr 23, 2025
49c737f
Fix comment typo.
sitaowang1998 Apr 23, 2025
e30b97c
Fix comment typo.
sitaowang1998 Apr 23, 2025
dfebb43
Fix comment typo.
sitaowang1998 Apr 23, 2025
60ac968
Use markdown instead of html in comment.
sitaowang1998 Apr 23, 2025
4162329
Add signal exit in docs
sitaowang1998 Apr 23, 2025
f576518
Merge branch 'worker_sigterm' of github.com:sitaowang1998/spider into…
sitaowang1998 Apr 23, 2025
e82151c
Improve docs based on coderabbit suggestions
sitaowang1998 Apr 23, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions docs/src/user-docs/guides-quick-start.md
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,21 @@ NOTE:
If you used a different set of arguments to set up the storage backend, ensure you update the
storage backend URL in the command.

# Exiting the cluster

To stop the cluster, send `SIGTERM` to the scheduler and all workers.

The scheduler finishes the current tasks (e.g., scheduling tasks to workers, garbage collection,
failure recovery, etc.), then exits with `SIGTERM`.

When a worker receives `SIGTERM`, if it has no task executor, it exits immediately with `SIGTERM`.

If the worker has a task executor, it sends a `SIGTERM` to the task executor and waits for it to
exit.
Normally, the task executor exits immediately, and the worker sets the task as failed. If the task
executor has a signal handler installed and catches `SIGTERM`, it completes the execution of the
task, and the worker handles the task output as usual. Then the worker exits with `SIGTERM`.

# Next steps

In future guides, we'll explain how to write more complex tasks, as well as how to leverage Spider's
Expand Down
8 changes: 6 additions & 2 deletions src/spider/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,8 @@ target_link_libraries(
target_link_libraries(spider_core PRIVATE fmt::fmt)

set(SPIDER_WORKER_SOURCES
worker/ChildPid.hpp
worker/ChildPid.cpp
worker/DllLoader.hpp
worker/DllLoader.cpp
worker/Process.hpp
Expand All @@ -67,7 +69,8 @@ set(SPIDER_WORKER_SOURCES
worker/message_pipe.hpp
worker/WorkerClient.hpp
worker/WorkerClient.cpp
utils/StopToken.hpp
utils/StopFlag.hpp
utils/StopFlag.cpp
CACHE INTERNAL
"spider worker source files"
)
Expand Down Expand Up @@ -126,7 +129,8 @@ set(SPIDER_SCHEDULER_SOURCES
scheduler/SchedulerMessage.hpp
scheduler/SchedulerServer.cpp
scheduler/SchedulerServer.hpp
utils/StopToken.hpp
utils/StopFlag.hpp
utils/StopFlag.cpp
CACHE INTERNAL
"spider scheduler source files"
)
Expand Down
10 changes: 4 additions & 6 deletions src/spider/scheduler/SchedulerServer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
#include "../storage/DataStorage.hpp"
#include "../storage/MetadataStorage.hpp"
#include "../storage/StorageConnection.hpp"
#include "../utils/StopToken.hpp"
#include "../utils/StopFlag.hpp"
#include "SchedulerMessage.hpp"
#include "SchedulerPolicy.hpp"

Expand All @@ -29,15 +29,13 @@ SchedulerServer::SchedulerServer(
std::shared_ptr<SchedulerPolicy> policy,
std::shared_ptr<core::MetadataStorage> metadata_store,
std::shared_ptr<core::DataStorage> data_store,
std::shared_ptr<core::StorageConnection> conn,
core::StopToken& stop_token
std::shared_ptr<core::StorageConnection> conn
)
: m_port{port},
m_policy{std::move(policy)},
m_metadata_store{std::move(metadata_store)},
m_data_store{std::move(data_store)},
m_conn{std::move(conn)},
m_stop_token{stop_token} {
m_conn{std::move(conn)} {
boost::asio::co_spawn(m_context, receive_message(), boost::asio::detached);
std::lock_guard const lock{m_mutex};
m_thread = std::make_unique<std::thread>([&] { m_context.run(); });
Expand Down Expand Up @@ -96,7 +94,7 @@ auto SchedulerServer::receive_message() -> boost::asio::awaitable<void> {
co_return;
} catch (boost::system::system_error& e) {
spdlog::error("Fail to accept connection: {}", e.what());
m_stop_token.request_stop();
spider::core::StopFlag::request_stop();
co_return;
}
}
Expand Down
6 changes: 1 addition & 5 deletions src/spider/scheduler/SchedulerServer.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
#include "../storage/DataStorage.hpp"
#include "../storage/MetadataStorage.hpp"
#include "../storage/StorageConnection.hpp"
#include "../utils/StopToken.hpp"
#include "SchedulerPolicy.hpp"

namespace spider::scheduler {
Expand All @@ -27,8 +26,7 @@ class SchedulerServer {
std::shared_ptr<SchedulerPolicy> policy,
std::shared_ptr<core::MetadataStorage> metadata_store,
std::shared_ptr<core::DataStorage> data_store,
std::shared_ptr<core::StorageConnection> conn,
core::StopToken& stop_token
std::shared_ptr<core::StorageConnection> conn
);

auto pause() -> void;
Expand All @@ -51,8 +49,6 @@ class SchedulerServer {

std::mutex m_mutex;
std::unique_ptr<std::thread> m_thread;

core::StopToken& m_stop_token;
};
} // namespace spider::scheduler

Expand Down
66 changes: 44 additions & 22 deletions src/spider/scheduler/scheduler.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
#include <cerrno>
#include <chrono>
#include <csignal>
#include <functional>
#include <memory>
#include <string>
Expand Down Expand Up @@ -26,20 +28,31 @@
#include "../storage/mysql/MySqlStorageFactory.hpp"
#include "../storage/StorageConnection.hpp"
#include "../storage/StorageFactory.hpp"
#include "../utils/StopToken.hpp"
#include "../utils/StopFlag.hpp"
#include "FifoPolicy.hpp"
#include "SchedulerPolicy.hpp"
#include "SchedulerServer.hpp"

constexpr int cCmdArgParseErr = 1;
constexpr int cStorageConnectionErr = 2;
constexpr int cSchedulerAddrErr = 3;
constexpr int cStorageErr = 4;
constexpr int cSignalHandleErr = 2;
constexpr int cStorageConnectionErr = 3;
constexpr int cSchedulerAddrErr = 4;
constexpr int cStorageErr = 5;
Comment thread
davidlion marked this conversation as resolved.

constexpr int cCleanupInterval = 1000;
constexpr int cRetryCount = 5;

namespace {
/*
* Signal handler for SIGTERM. Sets the stop flag to request a stop.
* @param signal The signal number.
*/
auto stop_scheduler_handler(int signal) -> void {
if (SIGTERM == signal) {
spider::core::StopFlag::request_stop();
}
}

auto parse_args(int const argc, char** argv) -> boost::program_options::variables_map {
boost::program_options::options_description desc;
desc.add_options()("help", "spider scheduler");
Expand Down Expand Up @@ -72,11 +85,10 @@ auto parse_args(int const argc, char** argv) -> boost::program_options::variable
auto heartbeat_loop(
std::shared_ptr<spider::core::StorageFactory> const& storage_factory,
std::shared_ptr<spider::core::MetadataStorage> const& metadata_store,
spider::core::Scheduler const& scheduler,
spider::core::StopToken& stop_token
spider::core::Scheduler const& scheduler
) -> void {
int fail_count = 0;
while (!stop_token.stop_requested()) {
while (!spider::core::StopFlag::is_stop_requested()) {
std::this_thread::sleep_for(std::chrono::seconds(1));
spdlog::debug("Updating heartbeat");
std::variant<std::unique_ptr<spider::core::StorageConnection>, spider::core::StorageErr>
Expand All @@ -102,18 +114,17 @@ auto heartbeat_loop(
fail_count = 0;
}
if (fail_count >= cRetryCount - 1) {
stop_token.request_stop();
spider::core::StopFlag::request_stop();
break;
}
}
}

auto cleanup_loop(
std::shared_ptr<spider::core::StorageFactory> const& storage_factory,
std::shared_ptr<spider::core::DataStorage> const& data_store,
spider::core::StopToken const& stop_token
std::shared_ptr<spider::core::DataStorage> const& data_store
) -> void {
while (!stop_token.stop_requested()) {
while (!spider::core::StopFlag::is_stop_requested()) {
std::this_thread::sleep_for(std::chrono::seconds(cCleanupInterval));
spdlog::debug("Starting cleanup");
std::variant<std::unique_ptr<spider::core::StorageConnection>, spider::core::StorageErr>
Expand All @@ -133,6 +144,8 @@ auto cleanup_loop(
spdlog::debug("Finished cleanup");
}
}

constexpr int cSignalExitBase = 128;
} // namespace

// NOLINTNEXTLINE(bugprone-exception-escape)
Expand Down Expand Up @@ -171,6 +184,18 @@ auto main(int argc, char** argv) -> int {
return cCmdArgParseErr;
}

// Ignore SIGTERM
// NOLINTBEGIN(misc-include-cleaner)
struct sigaction sig_action{};
sig_action.sa_handler = stop_scheduler_handler;
sigemptyset(&sig_action.sa_mask);
sig_action.sa_flags |= SA_RESTART;
if (0 != sigaction(SIGTERM, &sig_action, nullptr)) {
spdlog::error("Fail to install signal handler for SIGTERM: errno {}", errno);
return cSignalHandleErr;
}
// NOLINTEND(misc-include-cleaner)

// Create storages
std::shared_ptr<spider::core::StorageFactory> const storage_factory
= std::make_unique<spider::core::MySqlStorageFactory>(storage_url);
Expand Down Expand Up @@ -215,34 +240,26 @@ auto main(int argc, char** argv) -> int {
}

// Start scheduler server
spider::core::StopToken stop_token;
std::shared_ptr<spider::scheduler::SchedulerPolicy> const policy
= std::make_shared<spider::scheduler::FifoPolicy>(
scheduler_id,
metadata_store,
data_store,
conn
);
spider::scheduler::SchedulerServer
server{port, policy, metadata_store, data_store, conn, stop_token};
spider::scheduler::SchedulerServer server{port, policy, metadata_store, data_store, conn};

try {
// Start a thread that periodically updates the scheduler's heartbeat
std::thread heartbeat_thread{
heartbeat_loop,
std::cref(storage_factory),
std::cref(metadata_store),
std::ref(scheduler),
std::ref(stop_token),
std::ref(scheduler)
};

// Start a thread that periodically starts cleanup
std::thread cleanup_thread{
cleanup_loop,
std::cref(storage_factory),
std::cref(data_store),
std::ref(stop_token)
};
std::thread cleanup_thread{cleanup_loop, std::cref(storage_factory), std::cref(data_store)};

heartbeat_thread.join();
cleanup_thread.join();
Expand All @@ -251,5 +268,10 @@ auto main(int argc, char** argv) -> int {
spdlog::error("Failed to join thread: {}", e.what());
}

// If SIGTERM was caught and StopFlag is requested, set the exit value corresponding to SIGTERM.
if (spider::core::StopFlag::is_stop_requested()) {
return cSignalExitBase + SIGTERM;
}

return 0;
}
19 changes: 19 additions & 0 deletions src/spider/utils/StopFlag.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
#include "StopFlag.hpp"

#include <atomic>

namespace spider::core {
auto StopFlag::request_stop() -> void {
m_stop.test_and_set();
}

auto StopFlag::is_stop_requested() -> bool {
return m_stop.test();
}

auto StopFlag::reset() -> void {
m_stop.clear();
}

std::atomic_flag StopFlag::m_stop = ATOMIC_FLAG_INIT;
} // namespace spider::core
46 changes: 46 additions & 0 deletions src/spider/utils/StopFlag.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
#ifndef SPIDER_UTILS_STOPTOKEN_HPP
#define SPIDER_UTILS_STOPTOKEN_HPP

#include <atomic>

namespace spider::core {
/**
* @brief A singleton class that provides a stop flag for threads and signal handlers.
*
* User can call request_stop() to set the stop flag, and check if the stop flag is set.
* This class is thread-safe and signal-safe.
*/
class StopFlag {
public:
/*
* Request to token owners to stop.
*/
static auto request_stop() -> void;

/*
* @return A boolean indicating whether the stop was requested.
*/
[[nodiscard]] static auto is_stop_requested() -> bool;

/*
* Reset the stop token.
*/
static auto reset() -> void;

// Delete constructor
StopFlag() = delete;
// Delete copy constructor and assignment operator
StopFlag(StopFlag const&) = delete;
auto operator=(StopFlag const&) -> StopFlag& = delete;
// Delete move constructor and assignment operator
StopFlag(StopFlag&&) = delete;
auto operator=(StopFlag&&) -> StopFlag& = delete;
// Default destructor
~StopFlag() = default;

private:
static std::atomic_flag m_stop;
};
} // namespace spider::core

#endif
22 changes: 0 additions & 22 deletions src/spider/utils/StopToken.hpp

This file was deleted.

17 changes: 17 additions & 0 deletions src/spider/worker/ChildPid.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#include "ChildPid.hpp"

#include <unistd.h>

#include <csignal>

namespace spider::core {
auto ChildPid::get_pid() -> std::sig_atomic_t {
return m_pid;
}

auto ChildPid::set_pid(pid_t const pid) -> void {
m_pid = pid;
}

std::sig_atomic_t volatile ChildPid::m_pid = 0;
} // namespace spider::core
Loading