mirror of
https://github.com/Hestia-Homes/Model.git
synced 2026-07-19 17:03:02 +00:00
The modelling_e2e Lambda held up to ~4 concurrent Postgres connections per invocation: the read Session stayed open across the write loop (the catalogue was queried live and overrides were read per-Property), each per-Property Unit of Work opened a second, and the TaskOrchestrator ran on its own NullPool engine — so the pool needed pool_size=2 + max_overflow=1 just for the modelling work. Under 32 concurrent containers that approached RDS max_connections. Restructure the handler to read everything up front — overrides, Scenario, an in-memory catalogue snapshot, and stored Solar — through one short-lived read Session, close it, then write each Property in a sequential Unit of Work. The read and write Sessions no longer overlap, so the engine drops to pool_size=1, max_overflow=0. Fold the orchestrator onto the same pooled engine: its repos commit on every save, releasing the connection between bookkeeping calls, so it holds none during the work. One invocation now uses one connection at a time. The catalogue becomes a per-invocation snapshot (MaterialSnapshotRepository), mirroring ProductPostgresRepository.get exactly — same drift mapping, lowest-id pick, and errors — but priced after the Session closes. Transaction isolation is preserved: per-Property writes and orchestrator bookkeeping keep their own independent transactions, just drawn sequentially from a single connection. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
31 lines
1.2 KiB
Python
31 lines
1.2 KiB
Python
"""In-memory ``PropertyOverridesReader`` over a pre-fetched snapshot.
|
|
|
|
The modelling_e2e handler reads each Property's overrides inside its write loop.
|
|
Reading them live keeps a second DB Session open alongside the per-Property write
|
|
Unit of Work; pre-fetching every Property's overrides up front (one read pass,
|
|
then the read Session is closed) lets the loop run on a single DB connection. This
|
|
serves those pre-fetched snapshots behind the same ``PropertyOverridesReader``
|
|
port — a Property with no pre-fetched entry resolves to no overrides, exactly as
|
|
the Postgres reader returns an empty snapshot for a Property with no rows.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from collections.abc import Mapping
|
|
|
|
from repositories.property.property_overrides_reader import (
|
|
PropertyOverridesReader,
|
|
ResolvedPropertyOverrides,
|
|
)
|
|
|
|
_NO_OVERRIDES = ResolvedPropertyOverrides(rows=())
|
|
|
|
|
|
class InMemoryPropertyOverridesReader(PropertyOverridesReader):
|
|
def __init__(
|
|
self, by_property_id: Mapping[int, ResolvedPropertyOverrides]
|
|
) -> None:
|
|
self._by_property_id = dict(by_property_id)
|
|
|
|
def overrides_for(self, property_id: int) -> ResolvedPropertyOverrides:
|
|
return self._by_property_id.get(property_id, _NO_OVERRIDES)
|