| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168 |
- #include <spdlog/spdlog.h>
- #include <atomic>
- #include <csignal>
- #include <cstdlib>
- #include <string>
- #include <thread>
- #include <unistd.h>
- #include "smartbotic/common.hpp"
- #include "smartbotic/llm/config.hpp"
- #include "smartbotic/llm/grpc/server.hpp"
- #include "smartbotic/llm/server_config.hpp"
- namespace {
- // Global server pointer for signal handling
- smartbotic::llm::grpc::GrpcServer* g_server = nullptr;
- // Atomic flag for shutdown tracking
- std::atomic<bool> g_shutdown_requested{false};
- // Self-pipe for async-signal-safe notification
- int g_shutdown_pipe[2] = {-1, -1};
- void SignalHandler(int signal) {
- if (g_shutdown_requested.exchange(true)) {
- // Second signal - force exit
- const char* msg = "Received second signal, forcing immediate exit\n";
- [[maybe_unused]] auto n = write(STDERR_FILENO, msg, 48);
- std::_Exit(1);
- }
- // Write to pipe to notify shutdown thread (async-signal-safe)
- char sig = static_cast<char>(signal);
- [[maybe_unused]] auto n = write(g_shutdown_pipe[1], &sig, 1);
- }
- // Shutdown thread that waits for signal and calls gRPC Shutdown()
- void ShutdownThread() {
- char sig = 0;
- // Block until signal is received (read from pipe)
- ssize_t n = read(g_shutdown_pipe[0], &sig, 1);
- if (n > 0) {
- const char* signal_name = (sig == SIGINT) ? "SIGINT" : "SIGTERM";
- spdlog::info("Received {} ({}), initiating graceful shutdown...", signal_name,
- static_cast<int>(sig));
- // Safe to call gRPC Shutdown() from this thread (not from signal handler)
- if (g_server != nullptr) {
- g_server->RequestShutdown();
- }
- }
- }
- auto SetLogLevel(smartbotic::llm::LogLevel level) {
- switch (level) {
- case smartbotic::llm::LogLevel::kTrace:
- spdlog::set_level(spdlog::level::trace);
- break;
- case smartbotic::llm::LogLevel::kDebug:
- spdlog::set_level(spdlog::level::debug);
- break;
- case smartbotic::llm::LogLevel::kInfo:
- spdlog::set_level(spdlog::level::info);
- break;
- case smartbotic::llm::LogLevel::kWarn:
- spdlog::set_level(spdlog::level::warn);
- break;
- case smartbotic::llm::LogLevel::kError:
- spdlog::set_level(spdlog::level::err);
- break;
- case smartbotic::llm::LogLevel::kCritical:
- spdlog::set_level(spdlog::level::critical);
- break;
- case smartbotic::llm::LogLevel::kOff:
- spdlog::set_level(spdlog::level::off);
- break;
- }
- }
- } // namespace
- int main(int argc, char* argv[]) {
- // Initialize common logging first (with default settings)
- smartbotic::common::Initialize("smartbotic-llm");
- spdlog::info("SmartBotic LLM Service starting...");
- // Load configuration from file, environment, and command line
- auto config = smartbotic::llm::ConfigLoader::Load(argc, argv);
- // Apply configured log level
- SetLogLevel(config.log_level);
- // Print configuration
- smartbotic::llm::ConfigLoader::PrintConfig(config);
- // Create self-pipe for async-signal-safe shutdown notification
- if (pipe(g_shutdown_pipe) == -1) {
- spdlog::error("Failed to create shutdown pipe");
- smartbotic::common::Shutdown();
- return 1;
- }
- // Convert LlmConfig to ServerConfig for the gRPC server
- auto server_config = smartbotic::llm::ServerConfig::FromConfig(config);
- // Create and start the server
- smartbotic::llm::grpc::GrpcServer server(server_config);
- g_server = &server;
- // Start shutdown thread that will call gRPC Shutdown() when signaled
- std::thread shutdown_thread(ShutdownThread);
- // Set up signal handlers for graceful shutdown (SIGTERM/SIGINT)
- struct sigaction sa{};
- sa.sa_handler = SignalHandler;
- sigemptyset(&sa.sa_mask);
- sa.sa_flags = 0;
- if (sigaction(SIGINT, &sa, nullptr) == -1) {
- spdlog::error("Failed to set SIGINT handler");
- close(g_shutdown_pipe[1]);
- shutdown_thread.join();
- close(g_shutdown_pipe[0]);
- smartbotic::common::Shutdown();
- return 1;
- }
- if (sigaction(SIGTERM, &sa, nullptr) == -1) {
- spdlog::error("Failed to set SIGTERM handler");
- close(g_shutdown_pipe[1]);
- shutdown_thread.join();
- close(g_shutdown_pipe[0]);
- smartbotic::common::Shutdown();
- return 1;
- }
- spdlog::info("Signal handlers registered for SIGINT and SIGTERM");
- if (!server.Start()) {
- spdlog::error("Failed to start server");
- close(g_shutdown_pipe[1]);
- shutdown_thread.join();
- close(g_shutdown_pipe[0]);
- smartbotic::common::Shutdown();
- return 1;
- }
- // Wait for server to stop (either by signal or error)
- server.Wait();
- // Wait for shutdown thread to complete
- shutdown_thread.join();
- // Perform cleanup after Wait() returns (safe to do in main thread)
- server.Cleanup();
- // Close pipe
- close(g_shutdown_pipe[0]);
- close(g_shutdown_pipe[1]);
- spdlog::info("SmartBotic LLM Service shutdown complete");
- g_server = nullptr;
- smartbotic::common::Shutdown();
- return 0;
- }
|