mirror of
https://github.com/ferdzo/iotDashboard.git
synced 2026-04-05 01:06:24 +00:00
141 lines
4.2 KiB
Python
141 lines
4.2 KiB
Python
"""
|
|
Configuration management for the database writer service.
|
|
Loads settings from environment variables with sensible defaults.
|
|
"""
|
|
import os
|
|
from dataclasses import dataclass
|
|
from typing import Optional
|
|
import dotenv
|
|
|
|
dotenv.load_dotenv()
|
|
|
|
|
|
@dataclass
|
|
class RedisConfig:
|
|
"""Redis connection configuration"""
|
|
host: str
|
|
port: int = 6379
|
|
db: int = 0
|
|
password: Optional[str] = None
|
|
|
|
|
|
@dataclass
|
|
class DatabaseConfig:
|
|
"""Database connection configuration"""
|
|
url: Optional[str] = None
|
|
host: Optional[str] = None
|
|
port: int = 5432
|
|
name: Optional[str] = None
|
|
user: Optional[str] = None
|
|
password: Optional[str] = None
|
|
table_name: str = "sensor_readings"
|
|
enable_timescale: bool = False
|
|
|
|
def get_connection_string(self) -> str:
|
|
"""Build connection string from components or return URL"""
|
|
if self.url:
|
|
return self.url
|
|
|
|
if not all([self.host, self.name, self.user, self.password]):
|
|
raise ValueError("Either DATABASE_URL or all DB_* variables must be set")
|
|
|
|
return f"postgresql://{self.user}:{self.password}@{self.host}:{self.port}/{self.name}"
|
|
|
|
|
|
@dataclass
|
|
class ConsumerConfig:
|
|
"""Redis consumer group configuration"""
|
|
group_name: str = "db_writer"
|
|
consumer_name: str = "worker-01"
|
|
batch_size: int = 100
|
|
batch_timeout_sec: int = 5
|
|
processing_interval_sec: float = 1.0
|
|
block_time_ms: int = 5000
|
|
|
|
|
|
@dataclass
|
|
class StreamConfig:
|
|
"""Redis stream configuration"""
|
|
pattern: str = "mqtt_stream:*"
|
|
dead_letter_stream: str = "mqtt_stream:failed"
|
|
max_retries: int = 3
|
|
trim_maxlen: int = 10000 # Keep last N messages in each stream
|
|
|
|
|
|
@dataclass
|
|
class LogConfig:
|
|
"""Logging configuration"""
|
|
level: str = "INFO"
|
|
format: str = "json" # json or console
|
|
|
|
|
|
class Config:
|
|
"""Main configuration class"""
|
|
|
|
def __init__(self):
|
|
self.redis = RedisConfig(
|
|
host=os.getenv('REDIS_HOST', 'localhost'),
|
|
port=int(os.getenv('REDIS_PORT', 6379)),
|
|
db=int(os.getenv('REDIS_DB', 0)),
|
|
password=os.getenv('REDIS_PASSWORD', None) or None
|
|
)
|
|
|
|
self.database = DatabaseConfig(
|
|
url=os.getenv('DATABASE_URL', None),
|
|
host=os.getenv('DB_HOST', None),
|
|
port=int(os.getenv('DB_PORT', 5432)),
|
|
name=os.getenv('DB_NAME', None),
|
|
user=os.getenv('DB_USER', None),
|
|
password=os.getenv('DB_PASSWORD', None),
|
|
table_name=os.getenv('TABLE_NAME', 'sensor_readings'),
|
|
enable_timescale=os.getenv('ENABLE_TIMESCALE', 'false').lower() == 'true'
|
|
)
|
|
|
|
self.consumer = ConsumerConfig(
|
|
group_name=os.getenv('CONSUMER_GROUP_NAME', 'db_writer'),
|
|
consumer_name=os.getenv('CONSUMER_NAME', 'worker-01'),
|
|
batch_size=int(os.getenv('BATCH_SIZE', 100)),
|
|
batch_timeout_sec=int(os.getenv('BATCH_TIMEOUT_SEC', 5)),
|
|
processing_interval_sec=float(os.getenv('PROCESSING_INTERVAL_SEC', 1.0)),
|
|
block_time_ms=int(os.getenv('BLOCK_TIME_MS', 5000))
|
|
)
|
|
|
|
self.stream = StreamConfig(
|
|
pattern=os.getenv('STREAM_PATTERN', 'mqtt_stream:*'),
|
|
dead_letter_stream=os.getenv('DEAD_LETTER_STREAM', 'mqtt_stream:failed'),
|
|
max_retries=int(os.getenv('MAX_RETRIES', 3)),
|
|
trim_maxlen=int(os.getenv('TRIM_MAXLEN', 10000))
|
|
)
|
|
|
|
self.log = LogConfig(
|
|
level=os.getenv('LOG_LEVEL', 'INFO'),
|
|
format=os.getenv('LOG_FORMAT', 'json')
|
|
)
|
|
|
|
def validate(self):
|
|
"""Validate configuration"""
|
|
errors = []
|
|
|
|
# Validate Redis config
|
|
if not self.redis.host:
|
|
errors.append("REDIS_HOST is required")
|
|
|
|
# Validate database config
|
|
try:
|
|
self.database.get_connection_string()
|
|
except ValueError as e:
|
|
errors.append(str(e))
|
|
|
|
# Validate consumer config
|
|
if self.consumer.batch_size < 1:
|
|
errors.append("BATCH_SIZE must be >= 1")
|
|
|
|
if errors:
|
|
raise ValueError(f"Configuration errors: {', '.join(errors)}")
|
|
|
|
return True
|
|
|
|
|
|
# Global config instance
|
|
config = Config()
|