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
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 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 | |
validate_security_csp(v: str | None) -> str | None classmethod ¶
Reject a CSP that is empty or carries control characters.
The value is written straight into a response header. A CR or LF in it is response-header injection, letting a caller who controls the environment forge additional headers or a response body. Rejecting at settings-construction time fails the service at boot rather than silently serving a malformed header.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
v | str | None | The configured CSP string, or None. | required |
Returns:
| Type | Description |
|---|---|
str | None | The validated CSP string, or None when unset. |
Raises:
| Type | Description |
|---|---|
ValueError | If the value is blank, non-ASCII, or contains a control character. |
Source code in libs/tradai-common/src/tradai/common/base_settings.py
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
Source code in libs/tradai-common/src/tradai/common/logger_mixin.py
268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 | |
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