M8-T10: add WarmteLink serial worker manager

This commit is contained in:
2026-08-23 21:22:06 +02:00
parent afe653bafa
commit 4884a19e3d
6 changed files with 721 additions and 11 deletions
+14
View File
@@ -27,10 +27,21 @@ from app.services.meter_sources import (
create_source, delete_source, list_bindings, list_sources, update_binding, update_source,
)
from app.services import timezone as _tz_mod
from app.services.warmtelink_worker import warmtelink_worker_manager
router = APIRouter(prefix="/api/energy", tags=["api-energy-meter-sources"])
def _reconcile_warmtelink_after_commit() -> None:
"""Runtime convergence is best-effort; the already committed API result wins."""
try:
warmtelink_worker_manager.reconcile()
except Exception:
# The manager records individual source failures itself. Do not turn a
# successful durable create/update/delete into a misleading HTTP 500.
return
def _as_utc(value: datetime) -> datetime:
if value.tzinfo is None:
return value.replace(tzinfo=_tz_mod.local_tz()).astimezone(UTC)
@@ -118,6 +129,7 @@ def post_source(body: MeterSourceCreate, db: Session = Depends(get_db),
source = create_source(db, name=body.name, kind=body.kind, config=body.config, enabled=body.enabled)
db.commit()
db.refresh(source)
_reconcile_warmtelink_after_commit()
return _source_response(source)
except (SourceProfileError, MeterSourceError) as exc:
db.rollback()
@@ -138,6 +150,7 @@ def patch_source(source_uuid: str, body: MeterSourcePatch, db: Session = Depends
updated = update_source(db, source.id, name=body.name, enabled=body.enabled, config_patch=body.config)
db.commit()
db.refresh(updated)
_reconcile_warmtelink_after_commit()
return _source_response(updated)
except (SourceProfileError, MeterSourceError) as exc:
db.rollback()
@@ -156,6 +169,7 @@ def remove_source(source_uuid: str, db: Session = Depends(get_db),
try:
delete_source(db, source.id)
db.commit()
_reconcile_warmtelink_after_commit()
return Response(status_code=status.HTTP_204_NO_CONTENT)
except SourceDeleteRestrictedError as exc:
db.rollback()