diff --git a/applications/modelling_e2e/handler.py b/applications/modelling_e2e/handler.py index 9215a078c..b580a37d4 100644 --- a/applications/modelling_e2e/handler.py +++ b/applications/modelling_e2e/handler.py @@ -65,7 +65,7 @@ from domain.modelling.plan import Plan from domain.property.property import Property, PropertyIdentity from domain.property_baseline.calculator_rebaseliner import CalculatorRebaseliner from domain.sap10_calculator.calculator import Sap10Calculator -from domain.tasks.subtasks import SubTask +from domain.tasks.subtasks import SubTask, SubTaskFailure from domain.tasks.tasks import Source from harness.console import run_modelling from orchestration.task_orchestrator import TaskOrchestrator @@ -687,12 +687,21 @@ def handler( ) logger.info(f"property={pid} queued for write") + failed_properties: list[dict[str, Any]] = [] if trigger.subtask_id is not None: # Attach mode (ADR-0055): the whole batch runs under the # distributor's pre-created sub_task — the @task_handler wrapper is # already inside it — so no per-property children are created. + # Failures stay isolated per property (siblings continue) and are + # recorded on the sub_task after the surviving writes flush. for pid in property_ids: - _model_property(pid) + try: + _model_property(pid) + except Exception as exc: # noqa: BLE001 — recorded below + logger.exception(f"property={pid} failed") + failed_properties.append( + {"property_id": pid, "error": str(exc)} + ) else: # Fan the batch out into one child SubTask per property and run # them in a single batched pass: create all children, model each @@ -732,5 +741,18 @@ def handler( f"{[s['certificate_number'] for s in skipped_certs]}" ) + # Raised only after the surviving writes flushed: the failure is a + # record on the sub_task, never an SQS retry (ADR-0055). Recovery is a + # deliberate re-send of the sub_task's own inputs. + if failed_properties: + raise SubTaskFailure( + f"{len(failed_properties)} of {len(property_ids)} " + "properties failed", + details={ + "succeeded": len(property_ids) - len(failed_properties), + "failed": failed_properties, + }, + ) + finally: read_session.close()