Files
iotDashboard/services/db_write/db_writer.py

92 lines
2.9 KiB
Python

import logging
from typing import List
from sqlalchemy import create_engine, select
from sqlalchemy.orm import sessionmaker
from sqlalchemy.pool import QueuePool
from config import config
from schema import SensorReading
from models import SensorReading as SensorReadingModel
class DatabaseWriter:
"""
Database writer using SQLAlchemy.
Schema is defined in models.py and should be managed using Alembic migrations.
This class only handles data insertion, NOT schema creation.
To manage schema:
1. Edit models.py to define your schema
2. Generate migration: alembic revision --autogenerate -m "description"
3. Apply migration: alembic upgrade head
"""
def __init__(self):
self.logger = logging.getLogger(__name__)
# Initialize SQLAlchemy engine with connection pooling
connection_string = config.database.get_connection_string()
self.engine = create_engine(
connection_string,
poolclass=QueuePool,
pool_size=5,
max_overflow=10,
pool_pre_ping=True
)
# Create session factory
self.SessionLocal = sessionmaker(bind=self.engine)
self.logger.info("Database writer initialized")
def write_batch(self, readings: List[SensorReading]) -> bool:
"""Write a batch of sensor readings to the database"""
if not readings:
return True
session = self.SessionLocal()
try:
# Convert to database objects
db_objects = [
SensorReadingModel(
timestamp=reading.timestamp,
device_id=reading.device_id,
sensor_type=reading.sensor_type,
value=reading.value,
metadata=reading.metadata
)
for reading in readings
]
# Bulk insert
session.bulk_save_objects(db_objects)
session.commit()
self.logger.debug(f"Wrote {len(readings)} readings to database")
return True
except Exception as e:
self.logger.error(f"Failed to write batch: {e}")
session.rollback()
return False
finally:
session.close()
def health_check(self) -> bool:
"""Check if database connection is healthy"""
try:
with self.engine.connect() as conn:
result = conn.execute(select(1))
return result.fetchone()[0] == 1
except Exception as e:
self.logger.error(f"Database health check failed: {e}")
return False
def close(self):
"""Close database engine and all connections"""
if hasattr(self, 'engine') and self.engine:
self.engine.dispose()
self.logger.info("Database engine closed")