From d98e87a0d007d1589814d3b2e80ef59a44a2e027 Mon Sep 17 00:00:00 2001 From: Anthony Volk Date: Fri, 3 Jul 2026 18:46:07 +0200 Subject: [PATCH] Install importlib-metadata explicitly in Modal images logfire >=4.7 imports importlib_metadata unconditionally on Python 3.13 but stopped receiving it transitively, so the freshly rebuilt gateway and simulation images crash on import logfire. The gateway ASGI factory died at startup, hanging every request past Modal's HTTP window (303 redirects), which failed all beta integration tests and blocked the production deploy of the observability PR (#594). Co-Authored-By: Claude Opus 4.8 (1M context) --- projects/policyengine-api-simulation/src/modal/app.py | 4 ++++ .../policyengine-api-simulation/src/modal/gateway/app.py | 4 ++++ .../tests/test_modal_bundle_image.py | 7 +++++++ 3 files changed, 15 insertions(+) diff --git a/projects/policyengine-api-simulation/src/modal/app.py b/projects/policyengine-api-simulation/src/modal/app.py index b57666745..e2729c13a 100644 --- a/projects/policyengine-api-simulation/src/modal/app.py +++ b/projects/policyengine-api-simulation/src/modal/app.py @@ -144,6 +144,10 @@ def build_base_simulation_image() -> modal.Image: "fastapi>=0.115.0", "tables>=3.10.2", "logfire>=3.0.0", + # logfire imports importlib_metadata unconditionally but does + # not declare it as a dependency on Python 3.13, so install it + # explicitly or workers crash on ``import logfire``. + "importlib-metadata>=8", "policyengine-observability[fastapi]>=1.3.0,<2", ) .run_commands( diff --git a/projects/policyengine-api-simulation/src/modal/gateway/app.py b/projects/policyengine-api-simulation/src/modal/gateway/app.py index e2a48825d..64144453e 100644 --- a/projects/policyengine-api-simulation/src/modal/gateway/app.py +++ b/projects/policyengine-api-simulation/src/modal/gateway/app.py @@ -29,6 +29,10 @@ # the auth module at runtime here. "cryptography>=41.0.0", "logfire>=3.0.0", + # logfire imports importlib_metadata unconditionally but does not + # declare it as a dependency on Python 3.13, so install it + # explicitly or the container crashes at startup. + "importlib-metadata>=8", "policyengine-observability[fastapi]>=1.3.0,<2", ) .add_local_python_source( diff --git a/projects/policyengine-api-simulation/tests/test_modal_bundle_image.py b/projects/policyengine-api-simulation/tests/test_modal_bundle_image.py index a41227f68..1bb8c7596 100644 --- a/projects/policyengine-api-simulation/tests/test_modal_bundle_image.py +++ b/projects/policyengine-api-simulation/tests/test_modal_bundle_image.py @@ -95,6 +95,10 @@ def test_modal_image_uses_policyengine_bundle_install(monkeypatch): packages = pip_install_calls[0][1] assert "policyengine-observability[fastapi]>=1.3.0,<2" in packages assert "logfire>=3.0.0" in packages + # logfire needs importlib_metadata at import time on Python 3.13 but + # does not declare it; without the explicit install every worker + # crashes on ``import logfire``. + assert "importlib-metadata>=8" in packages runtime_secret_sets = { name: kwargs["secrets"] for name, kwargs in app.app.function_calls @@ -164,6 +168,9 @@ def test_gateway_image_installs_dual_observability(monkeypatch): packages = pip_install_calls[0][1] assert "policyengine-observability[fastapi]>=1.3.0,<2" in packages assert "logfire>=3.0.0" in packages + # Same importlib_metadata gap as the simulation image: without this the + # gateway ASGI factory dies in configure_logfire and every request 303s. + assert "importlib-metadata>=8" in packages function_kwargs = {name: kwargs for name, kwargs in app.app.function_calls} assert function_kwargs["web_app"]["secrets"] == [