Documentation Index
Fetch the complete documentation index at: https://docs.springtail.io/llms.txt
Use this file to discover all available pages before exploring further.
Springtail Initialization and Service Lifecycle
This module provides the bootstrapping, dependency ordering, lifecycle management, and shutdown coordination for Springtail services. It defines:- A generic service abstraction
- Multiple initialization entry points (normal, daemon, test, custom)
- Dependency-aware shutdown ordering
- Centralized signal handling for daemon execution
- Cross-service argument storage
- Deterministic startup and shutdown sequencing
Core Concepts
ServiceRunner
ServiceRunner is the base class for all services participating in Springtail initialization.- Encapsulates startup and shutdown logic for a service
- Provides a human-readable service name
- Enables ordered startup and reverse-order shutdown
start()is called in registration order- If any
start()fails, already-started services are stopped in reverse order stop()is always called during shutdown, even on failure paths
Initialization Entry Points:
Standard
Standard initialization for non-daemon processes is done usingspringtail_init() function.
- Initializes logging
- Sets up exception handling
- Loads properties (environment + optional Redis)
- Initializes telemetry
- Starts Redis manager
- Initializes property Redis cache
- No Redis loading
- No daemonization
- Logging mask explicitly provided
- Clean startup and teardown in a single process
Daemon process
Initialization for long-running daemon processes is done usingspringtail_init_daemon() function.
- Optional daemonization via fork()
- PID file creation
- Signal-based shutdown coordination
- Admin HTTP server startup
- Coordinator thread startup
- If
daemonize == true,fork()function is called and parent proce exits immediately, while child becomes session leader. - Standard file descriptors are STDIN/STDOUT/STDERR redirected to
/dev/null - PID written to
<pid_path>/<program_name>.pid
- Store cross-service arguments
- Arguments are available to services during initialization
- Stored before initialization so runners can retrieve them
- Initialize daemon runtime
- Optional daemonization
- PID file creation
- Logging and signal handling
- Admin server and coordinator startup
- Start the main service
ProxyServer::start()runs after infrastructure is ready
- Block until shutdown
springtail_daemon_run()waits for signals
- Graceful shutdown
- Services stop in dependency order
- Resources released deterministically
Unit tests initialization
Initialization of unit tests is done usingspringtail_init_test() function.
- Forces Redis loading
- No daemon logic
- Simplified logging setup
- Redis is enabled
- No daemon logic
- No blocking signal loop
- Can only be called once during the test program life time
Custom initialization
Fully custom initialization is done usingspringtail_init_custom() function.
- Embedding Springtail inside another process
- Only a subset of initialization services are needed
- Non-standard startup ordering
- Embedding Springtail inside another application
- Running a partial service stack
- Testing startup order interactions
- Avoiding Redis, admin servers, or coordinators
springtail_init_custom() responsibilities shift to you. You must provide all required runners and you control startup order.
Argument Passing Between Services
Arguments stored viaspringtail_store_arguments() are accessible during initialization and runtime.
Example:
- Type-safe via std::any
- Service-scoped
- Optional or required retrieval
- Fails on type mismatch
Built-in Service Runners
Logging
DefaultLoggingRunner:
Handles final logging and open telemetry shutdown.
LoggingRunner:
Initializes logging with optional overrides:
- Log filename
- Logging mask
- Daemon mode awareness
Properties
PropertiesRunner:
Loads configuration from:
- Environment
- Optional Redis
- Optional override file
PropertiesCacheRunner:
Initializes the Redis-backed configuration cache.
Daemon
DaemonRunner:
Handles process daemonization and PID management.
Exception Handling
ExceptionRunner:
Initializes signal handlers and backtrace support.
Redis
RedisMgrRunner:
Initializes and shuts down the Redis connection manager.
Coordinator Interface
CoordinatorRunner:
Starts the coordinator background thread.
Admin Interface
AdminServerRunner:
Starts and stops the admin HTTP server.
Service Registration and Shutdown
ServiceRegister
ServiceRegister is a singleton responsible for:- Owning all active services
- Enforcing startup order
- Enforcing reverse shutdown order
- Already-started services are stopped immediately
- Initialization aborts
Dependency Graph
Springtail defines an explicit service dependency graph which enforces correct shutdown ordering of the internal singleton services. This prevents resource teardown races. It uses topological sort on the predefined dependency graph. The sort is executed during runtime and will cause a fatal error is any cycle is detected. When a singleton service is initialized with a specific service id, it will be marked is active. During shutdown, topologically sorted list of services will be shutdown in the order defined by their dependencies.Graceful Shutdown
The shutdown is performed usingspringtail_daemon_run() function:
- SIGINT
- SIGTERM
- SIGQUIT
- SIGUSR1
- SIGUSR2
- The signal handlers for these signals are restored
- Shutdown proceeds in dependency order
springtail_shutdown() function:
- Uses precomputed dependency ordering
- Calls each service’s registered shutdown function
- Performs final Protobuf cleanup
Cross-Service Argument Storage
This functionality is needed when we have command line arguments that need to be passed to specificSingleton services.
It allows arbitrary typed arguments to be stored for the service that needs them and then retrieved by that service during initialization.
To store an argument, use the following function:
- Type-safe retrieval via std::any
- Optional enforcement of required arguments
- Fails on type mismatch