Services & Base Classes¶
Auto-generated API reference for TradAI service base classes.
BaseService¶
tradai.common.base_service.BaseService ¶
Bases: LoggerMixin, Generic[S]
Base class for all TradAI services.
Provides: - Settings injection with type-safe access via Generic[S] - Lifecycle hooks (startup/shutdown) for resource management - Health check endpoint using settings metadata - Hydra configuration factory method
Services must define a settings_class attribute pointing to their Settings class.
Attributes:
| Name | Type | Description |
|---|---|---|
settings_class | type[S] | Pydantic Settings class (must be overridden) |
settings | S | Type-safe validated settings instance (read-only property) |
Example
class BacktesterSettings(Settings): ... service_name: str = Field(default="Backtester") ... strategy: str ... timeframe: str ... class BacktesterService(BaseService[BacktesterSettings]): ... settings_class = BacktesterSettings ... ... async def startup(self) -> None: ... await super().startup() ... self.db = await connect_database() ... ... async def shutdown(self) -> None: ... await self.db.close() ... await super().shutdown() ...
Create from Hydra config¶
service = BacktesterService.from_hydra_cfg(cfg, "backtester") await service.startup()
Source code in libs/tradai-common/src/tradai/common/base_service.py
26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 | |
settings: S property ¶
Type-safe access to service settings.
health_service: HealthService property ¶
Access to health service for advanced health check operations.
register_health_checker(checker: HealthChecker) -> None ¶
Register a health checker for dependency monitoring.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
checker | HealthChecker | HealthChecker instance for a dependency | required |
Example
service.register_health_checker(RedisHealthChecker(redis_client))
Source code in libs/tradai-common/src/tradai/common/base_service.py
check_health() -> HealthResult async ¶
Perform async health check with all registered dependency checkers.
Executes all registered health checkers concurrently and returns aggregated result.
Returns:
| Type | Description |
|---|---|
HealthResult | HealthResult with overall status and individual check results |
Example
result = await service.check_health() if result.healthy: ... print("All systems operational")
Source code in libs/tradai-common/src/tradai/common/base_service.py
health_check() -> HealthResult ¶
Perform synchronous health check with all registered dependencies.
Uses sync wrapper around async health check. For async contexts, prefer check_health() instead.
Returns:
| Type | Description |
|---|---|
HealthResult | HealthResult with overall status and individual check results |
Example
result = service.health_check() result.healthy True result.service 'MyService'
Source code in libs/tradai-common/src/tradai/common/base_service.py
startup() -> None async ¶
Called on service startup. Override for initialization.
Use for: - Database connections - HTTP client setup - Cache warming - External service connections
Example
async def startup(self) -> None: ... await super().startup() ... self.db = await connect_database() ... self.client = httpx.AsyncClient()
Source code in libs/tradai-common/src/tradai/common/base_service.py
shutdown() -> None async ¶
Called on service shutdown. Override for cleanup.
Use for: - Close database connections - Flush buffers - Release resources
Example
async def shutdown(self) -> None: ... await self.client.aclose() ... await self.db.close() ... await super().shutdown()
Source code in libs/tradai-common/src/tradai/common/base_service.py
from_hydra_cfg(cfg: DictConfig, config_name: str) -> Self classmethod ¶
Create service from Hydra configuration.
Validates that settings_class is defined, then loads and validates configuration from Hydra.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
cfg | DictConfig | Hydra DictConfig object | required |
config_name | str | Configuration section name | required |
Returns:
| Type | Description |
|---|---|
Self | Service instance with validated settings |
Raises:
| Type | Description |
|---|---|
NotImplementedError | If settings_class not defined |
ValidationError | If configuration is invalid |
Example
config.yaml:¶
backtester:¶
strategy: PascalStrategy¶
timeframe: 1h¶
cfg = hydra.compose(config_name="config") service = BacktesterService.from_hydra_cfg(cfg, "backtester")
Source code in libs/tradai-common/src/tradai/common/base_service.py
Settings¶
tradai.common.base_settings.Settings ¶
Bases: BaseSettings
Base settings class for all TradAI services.
Provides common configuration fields that all services need. Services inherit and override defaults as needed.
Uses Pydantic for validation with strict mode: - frozen=True: Immutable after creation - extra="ignore": Ignore unknown env vars (services share .env files) - validate_assignment=True: Validate on field assignment
Supports loading configuration from: 1. Environment variables (with optional prefix in subclass) 2. Environment variable S3_CONFIG pointing to S3 URI 3. Local YAML file via Hydra
Example
class MyServiceSettings(Settings): ... service_name: str = Field(default="MyService") ... port: int = Field(default=8001) # Override default ... api_key: str # Service-specific required field ... settings = MyServiceSettings(api_key="secret") settings.service_name 'MyService'
Source code in libs/tradai-common/src/tradai/common/base_settings.py
26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 | |
parse_cors_origins(v: str | list[str] | None) -> list[str] classmethod ¶
Parse CORS origins from JSON list or comma-separated string.
Supports formats: - JSON list: '["http://localhost:3000","http://example.com"]' - Comma-separated: 'http://localhost:3000,http://example.com' - Already a list: ['http://localhost:3000', 'http://example.com']
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
v | str | list[str] | None | Input value (string, list, or None) | required |
Returns:
| Type | Description |
|---|---|
list[str] | List of origin URLs |
Source code in libs/tradai-common/src/tradai/common/base_settings.py
prepare_config(file_path: str, file_name: str = 'config.yaml', config_dir: str | Path | None = None) -> tuple[Path, str] classmethod ¶
Prepare configuration file path, downloading from S3 if needed.
Checks S3_CONFIG environment variable. If set, downloads config from S3. Otherwise, uses local file path.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
file_path | str | Path to caller file (typically file) | required |
file_name | str | Config filename (default: "config.yaml") | 'config.yaml' |
config_dir | str | Path | None | Explicit config directory. If None, finds project root and uses | None |
Returns:
| Type | Description |
|---|---|
tuple[Path, str] | Tuple of (config_directory, config_filename) |
Raises:
| Type | Description |
|---|---|
ValidationError | If S3 URI is invalid |
ExternalServiceError | If S3 download fails |
Example
Auto-detect project root¶
config_dir, config_file = Settings.prepare_config(file)
config_dir = /path/to/project/configs¶
config_file = config.yaml¶
Explicit config directory¶
config_dir, config_file = Settings.prepare_config(file, config_dir="./my_configs")
With S3 (S3_CONFIG=s3://bucket/configs/prod.yaml)¶
config_dir, config_file = Settings.prepare_config(file)
Downloads to /path/to/project/configs/prod.yaml¶
Source code in libs/tradai-common/src/tradai/common/base_settings.py
from_hydra_cfg(cfg: DictConfig, config_name: str) -> Settings classmethod ¶
Create settings from Hydra configuration.
Extracts a specific section from Hydra config and validates it.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
cfg | DictConfig | Hydra DictConfig object | required |
config_name | str | Section name in config (e.g., "backtester", "strategy") | required |
Returns:
| Type | Description |
|---|---|
Settings | Validated settings instance |
Raises:
| Type | Description |
|---|---|
ConfigurationError | If config section is missing |
ValidationError | If configuration values are invalid |
Example
config.yaml:¶
backtester:¶
service_name: Backtester¶
strategy: PascalStrategy¶
timeframe: 1h¶
cfg = hydra.compose(config_name="config") settings = BacktesterSettings.from_hydra_cfg(cfg, "backtester")
Source code in libs/tradai-common/src/tradai/common/base_settings.py
LoggerMixin¶
tradai.common.logger_mixin.LoggerMixin ¶
Mixin providing logging capabilities.
Uses cooperative multiple inheritance pattern - always calls super().init() to ensure proper MRO (Method Resolution Order) traversal.
Attributes:
| Name | Type | Description |
|---|---|---|
_logger | Logger | None | Internal logger instance |
LOGGER_FORMAT | str | Default log message format |
Example
class MyService(LoggerMixin): ... def do_work(self): ... self.logger.info("Working...") ... service = MyService() service.do_work() [2024-01-01][MyService][INFO] - Working...
Source code in libs/tradai-common/src/tradai/common/logger_mixin.py
17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 | |
logger: logging.Logger property ¶
Get logger instance.
Returns:
| Type | Description |
|---|---|
Logger | Configured logger |
Raises:
| Type | Description |
|---|---|
LoggerNotInitializedError | If logger not initialized |
get_hydra_logfile_dir_and_path() -> tuple[str, str] staticmethod ¶
Get Hydra output directory and log file path.
Useful when running services with Hydra configuration management.
Returns:
| Type | Description |
|---|---|
tuple[str, str] | Tuple of (output_dir, log_path) |
Example
log_dir, log_path = LoggerMixin.get_hydra_logfile_dir_and_path() print(f"Logs at: {log_path}") Logs at: outputs/2024-01-01/12-00-00/service.log