Common System 0.2.0
Common interfaces and patterns for system integration
Loading...
Searching...
No Matches
unified_bootstrapper.h
Go to the documentation of this file.
1// BSD 3-Clause License
2// Copyright (c) 2025, 🍀☀🌕🌥 🌊
3// See the LICENSE file in the project root for full license information.
4
25#pragma once
26
27#include "service_container.h"
29#include "../concepts/service.h"
31
32#include <atomic>
33#include <chrono>
34#include <csignal>
35#include <functional>
36#include <memory>
37#include <mutex>
38#include <string_view>
39#include <vector>
40
41namespace kcenon::common {
42namespace di {
43
52 bool enable_logging = true;
53
55 bool enable_monitoring = true;
56
58 bool enable_database = false;
59
61 bool enable_network = false;
62
64 std::string config_path;
65
67 std::chrono::milliseconds shutdown_timeout{30000};
68
71};
72
79using shutdown_hook = std::function<void(std::chrono::milliseconds remaining_timeout)>;
80
91
131public:
132 // Prevent instantiation
137
157 static VoidResult initialize(const bootstrapper_options& opts = {});
158
175 static VoidResult shutdown(
176 std::chrono::milliseconds timeout = std::chrono::seconds(30));
177
184 static service_container& services();
185
193 static bool is_initialized();
194
203 static bool is_shutdown_requested();
204
221 const std::string& name,
222 shutdown_hook hook);
223
230 static VoidResult unregister_shutdown_hook(const std::string& name);
231
240 static void request_shutdown(bool trigger_shutdown = false);
241
248
249 // ===== Module Registration =====
250
266 const std::string& name,
268
281 template<typename M>
283 static VoidResult register_module(M registrar);
284
297 static VoidResult unregister_module(const std::string& name);
298
304 static std::vector<std::string> registered_modules();
305
312 static bool is_module_registered(const std::string& name);
313
314private:
319
324
328 static void setup_default_shutdown_hooks();
329
333 static void setup_signal_handlers();
334
338 static void signal_handler(int signal);
339
343 static void execute_shutdown_hooks(std::chrono::milliseconds timeout);
344
345 // State
346 static std::atomic<bool> initialized_;
347 static std::atomic<bool> shutdown_requested_;
348 static std::mutex mutex_;
350
351 // Shutdown hooks
353 std::string name;
355 };
356 static std::vector<shutdown_hook_entry> shutdown_hooks_;
357
358 // Module registrations
364 static std::vector<module_entry> modules_;
365};
366
367// ============================================================================
368// unified_bootstrapper Implementation
369// ============================================================================
370
371inline std::atomic<bool> unified_bootstrapper::initialized_{false};
372inline std::atomic<bool> unified_bootstrapper::shutdown_requested_{false};
373inline std::mutex unified_bootstrapper::mutex_;
374inline bootstrapper_options unified_bootstrapper::options_;
375inline std::vector<unified_bootstrapper::shutdown_hook_entry>
377inline std::vector<unified_bootstrapper::module_entry>
379
381 std::lock_guard<std::mutex> lock(mutex_);
382
383 // Check if already initialized
384 if (initialized_.load()) {
385 return VoidResult::ok({});
386 }
387
388 // Store options
389 options_ = opts;
390
391 // Register core services
392 auto core_result = register_core_services();
393 if (core_result.is_err()) {
394 return core_result;
395 }
396
397 // Register optional services
398 auto optional_result = register_optional_services(opts);
399 if (optional_result.is_err()) {
400 // Cleanup on failure
402 // Reset module registration flags so they can be retried
403 for (auto& module : modules_) {
404 module.services_registered = false;
405 }
406 return optional_result;
407 }
408
409 // Set up default shutdown hooks
411
412 // Set up signal handlers
413 if (opts.register_signal_handlers) {
415 }
416
417 // Mark as initialized
418 initialized_.store(true);
419 shutdown_requested_.store(false);
420
421 return VoidResult::ok({});
422}
423
424inline VoidResult unified_bootstrapper::shutdown(std::chrono::milliseconds timeout) {
425 std::lock_guard<std::mutex> lock(mutex_);
426
427 if (!initialized_.load()) {
430 "System is not initialized",
431 "di::unified_bootstrapper"
432 );
433 }
434
435 // Mark shutdown as requested
436 shutdown_requested_.store(true);
437
438 // Execute shutdown hooks
439 execute_shutdown_hooks(timeout);
440
441 // Clear all services
443
444 // Clear shutdown hooks and modules
445 shutdown_hooks_.clear();
446 modules_.clear();
447
448 // Reset state
449 initialized_.store(false);
450 shutdown_requested_.store(false);
452
453 return VoidResult::ok({});
454}
455
457 if (!initialized_.load()) {
458 throw std::runtime_error(
459 "unified_bootstrapper: System is not initialized. "
460 "Call initialize() first."
461 );
462 }
464}
465
467 return initialized_.load();
468}
469
473
475 const std::string& name,
476 shutdown_hook hook) {
477
478 std::lock_guard<std::mutex> lock(mutex_);
479
480 if (!initialized_.load()) {
483 "System is not initialized",
484 "di::unified_bootstrapper"
485 );
486 }
487
488 // Check for duplicate
489 for (const auto& entry : shutdown_hooks_) {
490 if (entry.name == name) {
493 "Shutdown hook already registered: " + name,
494 "di::unified_bootstrapper"
495 );
496 }
497 }
498
499 shutdown_hooks_.push_back({name, std::move(hook)});
500 return VoidResult::ok({});
501}
502
504 const std::string& name) {
505
506 std::lock_guard<std::mutex> lock(mutex_);
507
508 auto it = std::find_if(shutdown_hooks_.begin(), shutdown_hooks_.end(),
509 [&name](const shutdown_hook_entry& entry) {
510 return entry.name == name;
511 });
512
513 if (it == shutdown_hooks_.end()) {
516 "Shutdown hook not found: " + name,
517 "di::unified_bootstrapper"
518 );
519 }
520
521 shutdown_hooks_.erase(it);
522 return VoidResult::ok({});
523}
524
525inline void unified_bootstrapper::request_shutdown(bool trigger_shutdown) {
526 shutdown_requested_.store(true);
527
528 if (trigger_shutdown) {
530 }
531}
532
534 std::lock_guard<std::mutex> lock(mutex_);
535 return options_;
536}
537
538// ============================================================================
539// Module Registration Implementation
540// ============================================================================
541
543 const std::string& name,
545
546 std::lock_guard<std::mutex> lock(mutex_);
547
548 // Check for duplicate
549 for (const auto& entry : modules_) {
550 if (entry.name == name) {
553 "Module already registered: " + name,
554 "di::unified_bootstrapper"
555 );
556 }
557 }
558
559 // If already initialized, register services immediately
560 if (initialized_.load()) {
561 auto& container = service_container::global();
562 auto result = fn(container);
563 if (!result.is_ok()) {
564 return result;
565 }
566 modules_.push_back({name, std::move(fn), true});
567 } else {
568 // Store for deferred registration during initialize()
569 modules_.push_back({name, std::move(fn), false});
570 }
571
572 return VoidResult::ok({});
573}
574
575template<typename M>
578 return register_module(
579 std::string(M::module_name()),
580 [r = std::move(registrar)](IServiceContainer& container) mutable {
581 return r.register_services(container);
582 }
583 );
584}
585
587 std::lock_guard<std::mutex> lock(mutex_);
588
589 auto it = std::find_if(modules_.begin(), modules_.end(),
590 [&name](const module_entry& entry) {
591 return entry.name == name;
592 });
593
594 if (it == modules_.end()) {
597 "Module not found: " + name,
598 "di::unified_bootstrapper"
599 );
600 }
601
602 modules_.erase(it);
603 return VoidResult::ok({});
604}
605
606inline std::vector<std::string> unified_bootstrapper::registered_modules() {
607 std::lock_guard<std::mutex> lock(mutex_);
608
609 std::vector<std::string> names;
610 names.reserve(modules_.size());
611 for (const auto& entry : modules_) {
612 names.push_back(entry.name);
613 }
614 return names;
615}
616
617inline bool unified_bootstrapper::is_module_registered(const std::string& name) {
618 std::lock_guard<std::mutex> lock(mutex_);
619
620 return std::find_if(modules_.begin(), modules_.end(),
621 [&name](const module_entry& entry) {
622 return entry.name == name;
623 }) != modules_.end();
624}
625
627 // Core services are minimal and always registered
628 // The service_container itself is already available via services()
629 // No additional core services are required at this time
630 //
631 // Future core services that might be registered here:
632 // - Default error handlers
633 // - Core diagnostics
634 // - System-level configuration providers
635 //
636 // For now, just ensure the container is initialized
637 // Subsystems register their own services via their adapter modules
638
639 return VoidResult::ok({});
640}
641
643 const bootstrapper_options& opts) {
644
645 // Optional services are registered based on configuration
646 // Each subsystem provides registration functions via adapters
647 // The registration is conditional based on:
648 // 1. bootstrapper_options flags (enable_logging, etc.)
649 // 2. Feature detection macros (KCENON_WITH_*_SYSTEM)
650 // 3. Dynamically registered modules via register_module()
651
652 auto& container = service_container::global();
653
654 // --- Compile-time subsystem integration (legacy) ---
655
656 // Logging services
657 if (opts.enable_logging) {
658#if KCENON_WITH_LOGGER_SYSTEM
659 // When logger_system is available and registered via register_module(),
660 // it will be handled below. The #ifdef path is kept for backward
661 // compatibility until all subsystems migrate to register_module().
662#endif
663 }
664
665 // Monitoring services
666 if (opts.enable_monitoring) {
667#if KCENON_WITH_MONITORING_SYSTEM
668 // Same as above - handled by register_module() when available.
669#endif
670 }
671
672 // Database services
673 if (opts.enable_database) {
674#if KCENON_WITH_DATABASE_SYSTEM
675 // Same as above - handled by register_module() when available.
676#endif
677 }
678
679 // Network services
680 if (opts.enable_network) {
681#if KCENON_WITH_NETWORK_SYSTEM
682 // Same as above - handled by register_module() when available.
683#endif
684 }
685
686 // --- Dynamic module registration ---
687 // Call registration functions for all modules registered before initialize()
688 for (auto& module : modules_) {
689 if (!module.services_registered) {
690 auto result = module.registration_fn(container);
691 if (!result.is_ok()) {
693 result.error().code,
694 "Module '" + module.name + "' registration failed: "
695 + result.error().message,
696 "di::unified_bootstrapper"
697 );
698 }
699 module.services_registered = true;
700 }
701 }
702
703 return VoidResult::ok({});
704}
705
707 // Register default shutdown hooks for core cleanup
708
709 // Service container cleanup hook (runs last, lowest priority)
710 shutdown_hooks_.push_back({
711 "service_container_cleanup",
712 [](std::chrono::milliseconds) {
713 // Container cleanup is handled by shutdown() itself
714 }
715 });
716}
717
719#ifndef _WIN32
720 // POSIX signal handling
721 struct sigaction sa;
722 sa.sa_handler = signal_handler;
723 sigemptyset(&sa.sa_mask);
724 sa.sa_flags = 0;
725
726 sigaction(SIGTERM, &sa, nullptr);
727 sigaction(SIGINT, &sa, nullptr);
728#else
729 // Windows signal handling
730 std::signal(SIGTERM, signal_handler);
731 std::signal(SIGINT, signal_handler);
732#endif
733}
734
736 (void)signal; // Unused parameter
737
738 // Request shutdown but don't trigger it from signal handler
739 // The main thread should check is_shutdown_requested() and call shutdown()
740 shutdown_requested_.store(true);
741}
742
744 std::chrono::milliseconds timeout) {
745
746 auto start = std::chrono::steady_clock::now();
747
748 // Execute hooks in reverse order (LIFO)
749 for (auto it = shutdown_hooks_.rbegin(); it != shutdown_hooks_.rend(); ++it) {
750 auto elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(
751 std::chrono::steady_clock::now() - start);
752 auto remaining = timeout - elapsed;
753
754 if (remaining <= std::chrono::milliseconds::zero()) {
755 // Timeout reached, skip remaining hooks
756 break;
757 }
758
759 try {
760 it->hook(remaining);
761 } catch (...) {
762 // Ignore exceptions during shutdown
763 }
764 }
765}
766
767} // namespace di
768} // namespace kcenon::common
Result type for error handling with member function support.
Definition core.cppm:165
static Result< T > ok(U &&value)
Create a successful result with value (static factory)
Definition core.h:223
Abstract interface for dependency injection containers.
Definition di.cppm:39
Concrete implementation of IServiceContainer.
static service_container & global()
Get the global service container instance.
VoidResult clear() override
Clear all registrations.
Coordinates system initialization and shutdown.
static bool is_shutdown_requested()
Check if shutdown has been requested.
static std::vector< std::string > registered_modules()
Get list of registered module names.
static bool is_initialized()
Check if the system is initialized.
static VoidResult unregister_module(const std::string &name)
Unregister a module.
static std::vector< shutdown_hook_entry > shutdown_hooks_
static void request_shutdown(bool trigger_shutdown=false)
Request graceful shutdown.
static bootstrapper_options get_options()
Get the initialization options.
unified_bootstrapper(const unified_bootstrapper &)=delete
static void setup_signal_handlers()
Set up signal handlers.
static bool is_module_registered(const std::string &name)
Check if a module is registered.
static VoidResult register_module(const std::string &name, module_registration_fn fn)
Register a module's service registration function.
static std::vector< module_entry > modules_
static VoidResult register_core_services()
Register core services that are always required.
static void signal_handler(int signal)
Signal handler function.
static VoidResult register_shutdown_hook(const std::string &name, shutdown_hook hook)
Register a shutdown hook.
static service_container & services()
Get the service container.
static VoidResult register_optional_services(const bootstrapper_options &opts)
Register optional services based on options.
static VoidResult shutdown(std::chrono::milliseconds timeout=std::chrono::seconds(30))
Shutdown the unified system gracefully.
static void setup_default_shutdown_hooks()
Set up default shutdown hooks.
unified_bootstrapper & operator=(const unified_bootstrapper &)=delete
static VoidResult initialize(const bootstrapper_options &opts={})
Initialize the unified system.
static VoidResult unregister_shutdown_hook(const std::string &name)
Unregister a shutdown hook.
static void execute_shutdown_hooks(std::chrono::milliseconds timeout)
Execute all shutdown hooks.
A class-based module registrar for ecosystem DI integration.
Definition service.h:342
System module integration flags.
Standard logger interface for all systems.
std::function< void(std::chrono::milliseconds remaining_timeout)> shutdown_hook
Shutdown hook callback type.
std::function< VoidResult(IServiceContainer &)> module_registration_fn
Module registration callback type.
constexpr int NOT_FOUND
Definition compat.h:32
constexpr int ALREADY_EXISTS
Definition compat.h:37
constexpr int NOT_INITIALIZED
Definition compat.h:36
Core interfaces.
Definition adapter.h:21
Result< T > make_error(int code, const std::string &message, const std::string &module="")
Create an error result with code and message.
Definition utilities.h:91
Result< std::monostate > VoidResult
Specialized Result for void operations.
Definition core.h:70
C++20 concepts for dependency injection and service container.
Implementation of the service container for dependency injection.
Configuration options for the unified bootstrapper.
bool enable_logging
Enable logging system services.
bool enable_database
Enable database system services.
bool register_signal_handlers
Register signal handlers (SIGTERM, SIGINT)
bool enable_network
Enable network system services.
bool enable_monitoring
Enable monitoring system services.
std::string config_path
Path to configuration file (optional)
std::chrono::milliseconds shutdown_timeout
Default shutdown timeout.
module_registration_fn registration_fn
bool services_registered
std::string name
std::string name
shutdown_hook hook